This is a sample code to reproduce problem.
# 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)
Run this code using Docker image provided by Docker Hub.
What makes difference?
(I'm sorry, my English is not good.)
This is a supplementary explanation.
I know sample code cause SystemStackError. I wrote sample code to cause SystemStackError.
I'd like to know reason of difference of "levels".
In this case, stack level is 137.
% docker container run -v (pwd):/mnt/my --rm -it ruby:2.5.0-alpine3.7 ruby -v /mnt/my/test.rb
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux-musl]
Traceback (most recent call last):
149: from /mnt/my/test.rb:11:in `<main>'
148: from /mnt/my/test.rb:8:in `f'
147: from /mnt/my/test.rb:8:in `each_value'
146: from /mnt/my/test.rb:8:in `block in f'
145: from /mnt/my/test.rb:8:in `f'
144: from /mnt/my/test.rb:8:in `each_value'
143: from /mnt/my/test.rb:8:in `block in f'
142: from /mnt/my/test.rb:8:in `f'
... 137 levels...
4: from /mnt/my/test.rb:8:in `f'
3: from /mnt/my/test.rb:8:in `each_value'
2: from /mnt/my/test.rb:8:in `block in f'
1: from /mnt/my/test.rb:8:in `f'
/mnt/my/test.rb:8:in `each_value': stack level too deep (SystemStackError)
But simple case, stack level is 13092.
% docker container run --rm -it ruby:2.5.0-alpine3.7 ruby -v -e 'def f; f; end; f'
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux-musl]
Traceback (most recent call last):
13104: from -e:1:in `<main>'
13103: from -e:1:in `f'
13102: from -e:1:in `f'
13101: from -e:1:in `f'
13100: from -e:1:in `f'
13099: from -e:1:in `f'
13098: from -e:1:in `f'
13097: from -e:1:in `f'
... 13092 levels...
4: from -e:1:in `f'
3: from -e:1:in `f'
2: from -e:1:in `f'
1: from -e:1:in `f'
-e:1:in `f': stack level too deep (SystemStackError)
In this case, stack level is 10067. There is a big difference from above case.
% docker container run -v (pwd):/mnt/my --rm -it 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:8:in `each_value': stack level too deep (SystemStackError)
from /mnt/my/test.rb:8:in `f'
from /mnt/my/test.rb:8:in `block in f'
from /mnt/my/test.rb:8:in `each_value'
from /mnt/my/test.rb:8:in `f'
from /mnt/my/test.rb:8:in `block in f'
from /mnt/my/test.rb:8:in `each_value'
from /mnt/my/test.rb:8:in `f'
from /mnt/my/test.rb:8:in `block in f'
... 10067 levels...
from /mnt/my/test.rb:8:in `block in f'
from /mnt/my/test.rb:8:in `each_value'
from /mnt/my/test.rb:8:in `f'
from /mnt/my/test.rb:11:in `<main>'
I show output of diff Dockerfile.
--- 2.4/alpine3.7/Dockerfile 2017-12-28 20:34:43.000000000 +0900
+++ 2.5/alpine3.7/Dockerfile 2017-12-28 20:34:43.000000000 +0900
@@ -7,9 +7,9 @@
echo 'update: --no-document'; \
} >> /usr/local/etc/gemrc
-ENV RUBY_MAJOR 2.4
-ENV RUBY_VERSION 2.4.3
-ENV RUBY_DOWNLOAD_SHA256 23677d40bf3b7621ba64593c978df40b1e026d8653c74a0599f0ead78ed92b51
+ENV RUBY_MAJOR 2.5
+ENV RUBY_VERSION 2.5.0
+ENV RUBY_DOWNLOAD_SHA256 1da0afed833a0dab94075221a615c14487b05d0c407f991c8080d576d985b49b
ENV RUBYGEMS_VERSION 2.7.4
ENV BUNDLER_VERSION 1.16.1
It means using same Alpine Linux. Just the Ruby is different.
In this case, stack level is 9866. This case uses Ruby 2.5.0, but it runs at Debian (not Alpine).
% docker container run -v (pwd):/mnt/my --rm -it ruby:2.5.0-stretch ruby -v /mnt/my/test.rb
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux]
Traceback (most recent call last):
9878: from /mnt/my/test.rb:11:in `<main>'
9877: from /mnt/my/test.rb:8:in `f'
9876: from /mnt/my/test.rb:8:in `each_value'
9875: from /mnt/my/test.rb:8:in `block in f'
9874: from /mnt/my/test.rb:8:in `f'
9873: from /mnt/my/test.rb:8:in `each_value'
9872: from /mnt/my/test.rb:8:in `block in f'
9871: from /mnt/my/test.rb:8:in `f'
... 9866 levels...
4: from /mnt/my/test.rb:8:in `f'
3: from /mnt/my/test.rb:8:in `each_value'
2: from /mnt/my/test.rb:8:in `block in f'
1: from /mnt/my/test.rb:8:in `f'
/mnt/my/test.rb:8:in `each_value': stack level too deep (SystemStackError)
We have seen this in some edge cases as well. We have confirmed that both the OS and Ruby stack sizes are the same in all cases. (alpine 2.4.3, alpine 2.5.0, and running 2.5.0 locally on MacOS)
The only differentiator we can find thusfar is that the Alpine 2.5.0 images are built off of Alpine 3.7, which builds Ruby with LibreSSL. The 2.4.3 image is built off of Alpine 3.4, which is still using OpenSSL. Our local 2.5.0 builds against OpenSSL do not show this "short" stack length.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With