Project

General

Profile

Bug #14387

Ruby 2.5 を Alpine Linux で実行すると比較的浅めで SystemStackError 例外になる

Added by koshigoe (Masataka SUZUKI) 28 days ago. Updated 17 days ago.

Status:
Open
Priority:
Normal
Assignee:
-
Target version:
-
ruby -v:
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux-musl]
[ruby-dev:50421]

Description

CircleCI で Alpine Linux を使って Ruby 2.5.0 で Rubocop を実行した時に遭遇した例外です(Ruby 2.4.3 では発生しませんでした)。

Ruby のバージョンによって、再帰が止められるまでの回数に大きな違いがあるのはなぜでしょうか?
これは、意図された挙動なのか、Ruby の変更によるものでは無く Alpine Linux 固有の問題なのか、教えていただく事は可能でしょうか?

Alpine Linux の Tread stack size が比較的小さい事で、Ruby 2.5.0 からこのような挙動になったのでしょうか?
https://wiki.musl-libc.org/functional-differences-from-glibc.html#Thread-stack-size

再現

問題の再現のため、以下の様な再帰するコードを実行します。

# test.rb
n = 100000
res = {}
1.upto(n).to_a.inject(res) do |r, i|
  r[i] = {}
end

def f(x)
  x.each_value { |v| f(v) }
end

f(res)

Ruby 2.4.3 で実行した場合、 10061 levels で例外があがりました。

% docker container run \
  -v (pwd):/mnt/my --rm \
  ruby:2.4.3-alpine3.7 \
  ruby -v /mnt/my/test.rb
ruby 2.4.3p205 (2017-12-14 revision 61247) [x86_64-linux-musl]
/mnt/my/test.rb:9:in `each_value': stack level too deep (SystemStackError)
        from /mnt/my/test.rb:9:in `f'
        from /mnt/my/test.rb:9:in `block in f'
        from /mnt/my/test.rb:9:in `each_value'
        from /mnt/my/test.rb:9:in `f'
        from /mnt/my/test.rb:9:in `block in f'
        from /mnt/my/test.rb:9:in `each_value'
        from /mnt/my/test.rb:9:in `f'
        from /mnt/my/test.rb:9:in `block in f'
         ... 10061 levels...
        from /mnt/my/test.rb:9:in `block in f'
        from /mnt/my/test.rb:9:in `each_value'
        from /mnt/my/test.rb:9:in `f'
        from /mnt/my/test.rb:12:in `<main>'

一方で Ruby 2.5.0 で実行した場合、 134 level で例外があがりました。

% docker container run \
  -v (pwd):/mnt/my --rm \
  test/ruby:trunk-alpine3.7 \
  ruby -v /mnt/my/test.rb
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux-musl]
/mnt/my/test.rb:9:in `each_value': stack level too deep (SystemStackError)
        from /mnt/my/test.rb:9:in `f'
        from /mnt/my/test.rb:9:in `block in f'
        from /mnt/my/test.rb:9:in `each_value'
        from /mnt/my/test.rb:9:in `f'
        from /mnt/my/test.rb:9:in `block in f'
        from /mnt/my/test.rb:9:in `each_value'
        from /mnt/my/test.rb:9:in `f'
        from /mnt/my/test.rb:9:in `block in f'
         ... 134 levels...
        from /mnt/my/test.rb:9:in `block in f'
        from /mnt/my/test.rb:9:in `each_value'
        from /mnt/my/test.rb:9:in `f'
        from /mnt/my/test.rb:12:in `<main>'

また、Ruby trunk で実行した場合は 2.5.0 同等の結果になりました。

ruby 2.6.0dev (2018-01-24 trunk 62017) [x86_64-linux-musl]
/mnt/my/test.rb:9:in `each_value': stack level too deep (SystemStackError)
        from /mnt/my/test.rb:9:in `f'
        from /mnt/my/test.rb:9:in `block in f'
        from /mnt/my/test.rb:9:in `each_value'
        from /mnt/my/test.rb:9:in `f'
        from /mnt/my/test.rb:9:in `block in f'
        from /mnt/my/test.rb:9:in `each_value'
        from /mnt/my/test.rb:9:in `f'
        from /mnt/my/test.rb:9:in `block in f'
         ... 134 levels...
        from /mnt/my/test.rb:9:in `block in f'
        from /mnt/my/test.rb:9:in `each_value'
        from /mnt/my/test.rb:9:in `f'
        from /mnt/my/test.rb:12:in `<main>'

※ trunk の Docker イメージを作った際の Dockerfile は以下。
https://gist.github.com/koshigoe/509be02a3580cdfc7a2cc45a4e6e44c5


Related issues

Related to Ruby trunk - Bug #13412: Infinite recursion with define_method may cause silent SEGV or cfp consistency errorClosed

History

#1 [ruby-dev:50433] Updated by wanabe (_ wanabe) 26 days ago

koshigoe (Masataka SUZUKI) wrote:

Ruby のバージョンによって、再帰が止められるまでの回数に大きな違いがあるのはなぜでしょうか?
これは、意図された挙動なのか、Ruby の変更によるものでは無く Alpine Linux 固有の問題なのか、教えていただく事は可能でしょうか?

Alpine Linux の Tread stack size が比較的小さい事で、Ruby 2.5.0 からこのような挙動になったのでしょうか?
https://wiki.musl-libc.org/functional-differences-from-glibc.html#Thread-stack-size

git bisect で確認したところ、 r59630 以降に今の挙動になっているようでした。
r59630 は [Bug #13412] に関連したコミットで、差分を見ると stack_check(th) というところから、スレットのスタックをチェックする処理が追加されていることがわかります。

ここから推測すると、おっしゃっている通り Alpine Linux で、あるいは musl で特有に見られる問題なのではないかと思われます。
意図的な挙動か、チェック内容を緩めるべきかどうか、pthread_attr_setstacksize やその他の方法で回避できるかまたそうするべきか、といったあたりはわかりませんでした。

#2 Updated by wanabe (_ wanabe) 26 days ago

  • Related to Bug #13412: Infinite recursion with define_method may cause silent SEGV or cfp consistency error added

#3 [ruby-dev:50435] Updated by scardon (Daniel Leong) 25 days ago

https://qiita.com/koshigoe/items/7acebbab7b44fa2b35bc

This is the post that spin off this issue ticket.
There are more information in there.

Hope we could get some form of resolution for Alpine users.

#4 [ruby-dev:50436] Updated by mame (Yusuke Endoh) 25 days ago

環境変数 RUBY_THREAD_MACHINE_STACK_SIZE に 1048576 とか大きい値を設定してみたら動きますか?
これで pthread_attr_setstacksize に渡すスタックサイズを調整できます。

なお、この設定は RubyVM::DEFAULT_PARAMS で読み出すことができます。

$ ruby -ve 'p RubyVM::DEFAULT_PARAMS[:thread_machine_stack_size]'
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux]
1048576

$ RUBY_THREAD_MACHINE_STACK_SIZE=80000 ruby -ve 'p RubyVM::DEFAULT_PARAMS[:thread_machine_stack_size]'
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux]
131072

#5 [ruby-dev:50444] Updated by craigjbass (Craig Bass) 22 days ago

wanabe (_ wanabe) wrote:

koshigoe (Masataka SUZUKI) wrote:

Ruby のバージョンによって、再帰が止められるまでの回数に大きな違いがあるのはなぜでしょうか?
これは、意図された挙動なのか、Ruby の変更によるものでは無く Alpine Linux 固有の問題なのか、教えていただく事は可能でしょうか?

Alpine Linux の Tread stack size が比較的小さい事で、Ruby 2.5.0 からこのような挙動になったのでしょうか?
https://wiki.musl-libc.org/functional-differences-from-glibc.html#Thread-stack-size

git bisect で確認したところ、 r59630 以降に今の挙動になっているようでした。
r59630 は [Bug #13412] に関連したコミットで、差分を見ると stack_check(th) というところから、スレットのスタックをチェックする処理が追加されていることがわかります。

ここから推測すると、おっしゃっている通り Alpine Linux で、あるいは musl で特有に見られる問題なのではないかと思われます。
意図的な挙動か、チェック内容を緩めるべきかどうか、pthread_attr_setstacksize やその他の方法で回避できるかまたそうするべきか、といったあたりはわかりませんでした。

I've also come across this issue: https://github.com/rspec/rspec-support/pull/343

mame (Yusuke Endoh) wrote:

環境変数 RUBY_THREAD_MACHINE_STACK_SIZE に 1048576 とか大きい値を設定してみたら動きますか?
これで pthread_attr_setstacksize に渡すスタックサイズを調整できます。

なお、この設定は RubyVM::DEFAULT_PARAMS で読み出すことができます。

$ ruby -ve 'p RubyVM::DEFAULT_PARAMS[:thread_machine_stack_size]'
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux]
1048576

$ RUBY_THREAD_MACHINE_STACK_SIZE=80000 ruby -ve 'p RubyVM::DEFAULT_PARAMS[:thread_machine_stack_size]'
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux]
131072

#6 [ruby-dev:50451] Updated by scardon (Daniel Leong) 22 days ago

/app # ruby -ve 'p RubyVM::DEFAULT_PARAMS[:thread_machine_stack_size]'
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux-musl]
1048576
/app # RUBY_THREAD_MACHINE_STACK_SIZE=100000 ruby -ve 'p RubyVM::DEFAULT_PARAMS[:thread_machine_stack_size]'
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux-musl]
131072
/app # RUBY_THREAD_MACHINE_STACK_SIZE=500000 ruby -ve 'p RubyVM::DEFAULT_PARAMS[:thread_machine_stack_size]'
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux-musl]
503808
/app # RUBY_THREAD_MACHINE_STACK_SIZE=100000 rubycritic -f html --no-browser app lib
RubyCritic can provide more feedback if you use a Git, Mercurial or Perforce repository. Churn will not be calculated.
Traceback (most recent call last):
    165: from /usr/local/bundle/bin/rubycritic:23:in `<main>'
    164: from /usr/local/bundle/bin/rubycritic:23:in `load'
    163: from /usr/local/bundle/gems/rubycritic-3.3.0/bin/rubycritic:10:in `<top (required)>'
    162: from /usr/local/bundle/gems/rubycritic-3.3.0/lib/rubycritic/cli/application.rb:20:in `execute'
    161: from /usr/local/bundle/gems/rubycritic-3.3.0/lib/rubycritic/commands/default.rb:19:in `execute'
    160: from /usr/local/bundle/gems/rubycritic-3.3.0/lib/rubycritic/commands/default.rb:24:in `critique'
    159: from /usr/local/bundle/gems/rubycritic-3.3.0/lib/rubycritic/analysers_runner.rb:27:in `run'
    158: from /usr/local/bundle/gems/rubycritic-3.3.0/lib/rubycritic/analysers_runner.rb:27:in `each'
     ... 153 levels...
      4: from /usr/local/bundle/gems/sexp_processor-4.10.0/lib/sexp.rb:223:in `each'
      3: from /usr/local/bundle/gems/sexp_processor-4.10.0/lib/sexp.rb:223:in `block in mass'
      2: from /usr/local/bundle/gems/sexp_processor-4.10.0/lib/sexp.rb:223:in `mass'
      1: from /usr/local/bundle/gems/sexp_processor-4.10.0/lib/sexp.rb:223:in `inject'
/usr/local/bundle/gems/sexp_processor-4.10.0/lib/sexp.rb:223:in `each': stack level too deep (SystemStackError)
/app # RUBY_THREAD_MACHINE_STACK_SIZE=500000 rubycritic -f html --no-browser app lib
RubyCritic can provide more feedback if you use a Git, Mercurial or Perforce repository. Churn will not be calculated.
Traceback (most recent call last):
    165: from /usr/local/bundle/bin/rubycritic:23:in `<main>'
    164: from /usr/local/bundle/bin/rubycritic:23:in `load'
    163: from /usr/local/bundle/gems/rubycritic-3.3.0/bin/rubycritic:10:in `<top (required)>'
    162: from /usr/local/bundle/gems/rubycritic-3.3.0/lib/rubycritic/cli/application.rb:20:in `execute'
    161: from /usr/local/bundle/gems/rubycritic-3.3.0/lib/rubycritic/commands/default.rb:19:in `execute'
    160: from /usr/local/bundle/gems/rubycritic-3.3.0/lib/rubycritic/commands/default.rb:24:in `critique'
    159: from /usr/local/bundle/gems/rubycritic-3.3.0/lib/rubycritic/analysers_runner.rb:27:in `run'
    158: from /usr/local/bundle/gems/rubycritic-3.3.0/lib/rubycritic/analysers_runner.rb:27:in `each'
     ... 153 levels...
      4: from /usr/local/bundle/gems/sexp_processor-4.10.0/lib/sexp.rb:223:in `each'
      3: from /usr/local/bundle/gems/sexp_processor-4.10.0/lib/sexp.rb:223:in `block in mass'
      2: from /usr/local/bundle/gems/sexp_processor-4.10.0/lib/sexp.rb:223:in `mass'
      1: from /usr/local/bundle/gems/sexp_processor-4.10.0/lib/sexp.rb:223:in `inject'
/usr/local/bundle/gems/sexp_processor-4.10.0/lib/sexp.rb:223:in `each': stack level too deep (SystemStackError)
/app # rubycritic -f html --no-browser app lib
RubyCritic can provide more feedback if you use a Git, Mercurial or Perforce repository. Churn will not be calculated.
Traceback (most recent call last):
    164: from /usr/local/bundle/bin/rubycritic:23:in `<main>'
    163: from /usr/local/bundle/bin/rubycritic:23:in `load'
    162: from /usr/local/bundle/gems/rubycritic-3.3.0/bin/rubycritic:10:in `<top (required)>'
    161: from /usr/local/bundle/gems/rubycritic-3.3.0/lib/rubycritic/cli/application.rb:20:in `execute'
    160: from /usr/local/bundle/gems/rubycritic-3.3.0/lib/rubycritic/commands/default.rb:19:in `execute'
    159: from /usr/local/bundle/gems/rubycritic-3.3.0/lib/rubycritic/commands/default.rb:24:in `critique'
    158: from /usr/local/bundle/gems/rubycritic-3.3.0/lib/rubycritic/analysers_runner.rb:27:in `run'
    157: from /usr/local/bundle/gems/rubycritic-3.3.0/lib/rubycritic/analysers_runner.rb:27:in `each'
     ... 152 levels...
      4: from /usr/local/bundle/gems/sexp_processor-4.10.0/lib/sexp.rb:223:in `inject'
      3: from /usr/local/bundle/gems/sexp_processor-4.10.0/lib/sexp.rb:223:in `each'
      2: from /usr/local/bundle/gems/sexp_processor-4.10.0/lib/sexp.rb:223:in `block in mass'
      1: from /usr/local/bundle/gems/sexp_processor-4.10.0/lib/sexp.rb:223:in `mass'
/usr/local/bundle/gems/sexp_processor-4.10.0/lib/sexp.rb:223:in `inject': stack level too deep (SystemStackError)

This is some output with the rubycritic gem trying to parse a deeply nested AST.
Below is some output with the brakeman gem trying to parse the same deeply nested AST.

/app # ruby -ve 'p RubyVM::DEFAULT_PARAMS[:thread_machine_stack_size]'
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux-musl]
1048576
/app # RUBY_THREAD_MACHINE_STACK_SIZE=100000 ruby -ve 'p RubyVM::DEFAULT_PARAMS[:thread_machine_stack_size]'
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux-musl]
131072
/app # RUBY_THREAD_MACHINE_STACK_SIZE=500000 ruby -ve 'p RubyVM::DEFAULT_PARAMS[:thread_machine_stack_size]'
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux-musl]
503808
/app # brakeman -o brakeman-output.json --no-progress --separate-models --no-branching
Loading scanner...
Processing application in /app
Processing gems...
[Notice] Detected Rails 5 application
Processing configuration...
[Notice] Escaping HTML by default
Parsing files...
Processing initializers...
Processing libs...
Traceback (most recent call last):
    254: from /usr/local/bundle/bin/brakeman:23:in `<main>'
    253: from /usr/local/bundle/bin/brakeman:23:in `load'
    252: from /usr/local/bundle/gems/brakeman-4.1.1/bin/brakeman:8:in `<top (required)>'
    251: from /usr/local/bundle/gems/brakeman-4.1.1/lib/brakeman/commandline.rb:20:in `start'
    250: from /usr/local/bundle/gems/brakeman-4.1.1/lib/brakeman/commandline.rb:35:in `run'
    249: from /usr/local/bundle/gems/brakeman-4.1.1/lib/brakeman/commandline.rb:142:in `run_report'
    248: from /usr/local/bundle/gems/brakeman-4.1.1/lib/brakeman/commandline.rb:118:in `regular_report'
    247: from /usr/local/bundle/gems/brakeman-4.1.1/lib/brakeman/commandline.rb:133:in `run_brakeman'
     ... 242 levels...
      4: from /usr/local/bundle/gems/brakeman-4.1.1/lib/ruby_parser/bm_sexp.rb:106:in `hash'
      3: from /usr/local/bundle/gems/brakeman-4.1.1/lib/ruby_parser/bm_sexp.rb:106:in `hash'
      2: from /usr/local/bundle/gems/brakeman-4.1.1/lib/ruby_parser/bm_sexp.rb:106:in `hash'
      1: from /usr/local/bundle/gems/brakeman-4.1.1/lib/ruby_parser/bm_sexp.rb:106:in `hash'
/usr/local/bundle/gems/brakeman-4.1.1/lib/ruby_parser/bm_sexp.rb:106:in `hash': stack level too deep (SystemStackError)
/app # RUBY_THREAD_MACHINE_STACK_SIZE=100000 brakeman -o brakeman-output.json --no-progress --separate-models --no-branching
Loading scanner...
Processing application in /app
Processing gems...
[Notice] Detected Rails 5 application
Processing configuration...
[Notice] Escaping HTML by default
Parsing files...
Processing initializers...
Processing libs...
Traceback (most recent call last):
    256: from /usr/local/bundle/bin/brakeman:23:in `<main>'
    255: from /usr/local/bundle/bin/brakeman:23:in `load'
    254: from /usr/local/bundle/gems/brakeman-4.1.1/bin/brakeman:8:in `<top (required)>'
    253: from /usr/local/bundle/gems/brakeman-4.1.1/lib/brakeman/commandline.rb:20:in `start'
    252: from /usr/local/bundle/gems/brakeman-4.1.1/lib/brakeman/commandline.rb:35:in `run'
    251: from /usr/local/bundle/gems/brakeman-4.1.1/lib/brakeman/commandline.rb:142:in `run_report'
    250: from /usr/local/bundle/gems/brakeman-4.1.1/lib/brakeman/commandline.rb:118:in `regular_report'
    249: from /usr/local/bundle/gems/brakeman-4.1.1/lib/brakeman/commandline.rb:133:in `run_brakeman'
     ... 244 levels...
      4: from /usr/local/bundle/gems/brakeman-4.1.1/lib/ruby_parser/bm_sexp.rb:106:in `hash'
      3: from /usr/local/bundle/gems/brakeman-4.1.1/lib/ruby_parser/bm_sexp.rb:106:in `hash'
      2: from /usr/local/bundle/gems/brakeman-4.1.1/lib/ruby_parser/bm_sexp.rb:106:in `hash'
      1: from /usr/local/bundle/gems/brakeman-4.1.1/lib/ruby_parser/bm_sexp.rb:106:in `hash'
/usr/local/bundle/gems/brakeman-4.1.1/lib/ruby_parser/bm_sexp.rb:106:in `hash': stack level too deep (SystemStackError)
/app # RUBY_THREAD_MACHINE_STACK_SIZE=500000 brakeman -o brakeman-output.json --no-progress --separate-models --no-branching
Loading scanner...
Processing application in /app
Processing gems...
[Notice] Detected Rails 5 application
Processing configuration...
[Notice] Escaping HTML by default
Parsing files...
Processing initializers...
Processing libs...
Traceback (most recent call last):
    256: from /usr/local/bundle/bin/brakeman:23:in `<main>'
    255: from /usr/local/bundle/bin/brakeman:23:in `load'
    254: from /usr/local/bundle/gems/brakeman-4.1.1/bin/brakeman:8:in `<top (required)>'
    253: from /usr/local/bundle/gems/brakeman-4.1.1/lib/brakeman/commandline.rb:20:in `start'
    252: from /usr/local/bundle/gems/brakeman-4.1.1/lib/brakeman/commandline.rb:35:in `run'
    251: from /usr/local/bundle/gems/brakeman-4.1.1/lib/brakeman/commandline.rb:142:in `run_report'
    250: from /usr/local/bundle/gems/brakeman-4.1.1/lib/brakeman/commandline.rb:118:in `regular_report'
    249: from /usr/local/bundle/gems/brakeman-4.1.1/lib/brakeman/commandline.rb:133:in `run_brakeman'
     ... 244 levels...
      4: from /usr/local/bundle/gems/brakeman-4.1.1/lib/ruby_parser/bm_sexp.rb:106:in `hash'
      3: from /usr/local/bundle/gems/brakeman-4.1.1/lib/ruby_parser/bm_sexp.rb:106:in `hash'
      2: from /usr/local/bundle/gems/brakeman-4.1.1/lib/ruby_parser/bm_sexp.rb:106:in `hash'
      1: from /usr/local/bundle/gems/brakeman-4.1.1/lib/ruby_parser/bm_sexp.rb:106:in `hash'
/usr/local/bundle/gems/brakeman-4.1.1/lib/ruby_parser/bm_sexp.rb:106:in `hash': stack level too deep (SystemStackError)

Both brakeman and rubycritic never would have such error when we were using ruby 2.4

#7 [ruby-dev:50452] Updated by wanabe (_ wanabe) 21 days ago

mame (Yusuke Endoh) wrote:

環境変数 RUBY_THREAD_MACHINE_STACK_SIZE に 1048576 とか大きい値を設定してみたら動きますか?
これで pthread_attr_setstacksize に渡すスタックサイズを調整できます。

スレッドといってもメインスレッドしか存在せず、native_thread_create() が呼び出されるわけではないので、残念ながら動作は変化していないようです。

/work # ./miniruby test.rb 2>&1|grep level
test.rb:8:in `each_value': stack level too deep (SystemStackError)
     ... 194 levels...
/work # RUBY_THREAD_MACHINE_STACK_SIZE=1048576 ./miniruby test.rb 2>&1|grep level
test.rb:8:in `each_value': stack level too deep (SystemStackError)
     ... 188 levels...

スレッドで包んでやると期待通りの挙動が得られました。

/work # RUBY_THREAD_MACHINE_STACK_SIZE=1048576 ./miniruby -e 'Thread.new{ load "test.rb" }.join' 2>&1|grep level
test.rb:8:in `each_value': stack level too deep (SystemStackError)
     ... 1720 levels...
test.rb:8:in `each_value': stack level too deep (SystemStackError)
     ... 1720 levels...

以下のようなテストプログラムを動かすと、Alpine musl 環境では rlim_cur の値と pthread_attr_getstacksize の値が大きく異なることがわかりました。
このあたりが関係しているのではないでしょうか。

#include <stdio.h>
#include <sys/resource.h>
#include <pthread.h>

int main (void) {
  struct rlimit limit;
  pthread_attr_t attr;
  size_t stacksize;

  getrlimit(RLIMIT_STACK, &limit);
  pthread_attr_init(&attr);
  pthread_attr_getstacksize(&attr, &stacksize);
  pthread_attr_destroy(&attr);
  printf("rlim_cur: %ld\nrlim_max: %ld\nstacksize: %ld\n", (size_t)limit.rlim_cur, (size_t)limit.rlim_max, stacksize);
  return 0;
}
/work # gcc -pthread test.c && ./a.out
rlim_cur: 8388608
rlim_max: -1
stacksize: 81920

なお、同じプログラムを ubuntu 18.04 上で動かした場合には両者は一致しました。

$ gcc -pthread test.c && ./a.out
rlim_cur: 8388608
rlim_max: -1
stacksize: 8388608

#8 [ruby-dev:50463] Updated by jhealy (James Healy) 17 days ago

There's a very similar sounding issue being discussed on the python bug tracker: https://bugs.python.org/issue32307

Also available in: Atom PDF