method_missing 傳遞 splat argument 會噴 SystemStackError
- Backend
- 30 Sep, 2020
最近遇到一個因為 splat argument 導致噴 SystemStackError 的案例,研究了半天發現是使用 method_missing 才會遇到
最近工作上遇到一個案例,是呼叫某個函式會噴 SystemStackError,google 發現了類似的事情 https://github.com/redis/redis-rb/issues/264
Thanks for the report. This is now fixed on master. The problem was that some commands used argument splatting to pass their arguments to other functions. Argument splatting uses the Ruby stack, and can therefore result in a stack overflow when large arrays are splatted.
看起來是因為用 splat argument 傳遞參數太長導致 stack overflow。但是自己怎麼都無法簡單重現出來。
後來找到這個 https://bugs.ruby-lang.org/issues/10440 https://github.com/ruby/ruby/commit/5d1f152fa342f6bb5fa9b546e3971843ee81c6b1
發現在 Ruby 2.2 之後就解掉了,我自己裝 Ruby 2.1 的確就有辦法重現沒錯。不過工作用的環境是 Ruby 2.5.7 遇到的。
後來終於找到差異,原來是 method_missing 才會遇到:
class A
def a(*args)
puts args.size
end
end
class B
def method_missing(*args)
puts args.size
end
end
A.new.a(*(1..1_000_000).to_a) # => 1000000
B.new.b(*(1..1_000_000).to_a) # => SystemStackError: stack level too deep