exported from https://nippo.wikihub.io/@_ksss_/20160722124458
mruby本体に2つバグがあった。
一つめ
Struct.new(:a) do def foo end end
とすると、foo
メソッドはStruct.newで作られた新しいclassのメソッドになることを期待するが、
なんと、Struct
classのメソッドになるというもの。ここでメソッドを定義してしまうと、全部のStruct classの小クラスで共有されちゃう。
しかもself
はちゃんとStruct classの小クラスになっていて気が付きにくく邪悪。
ほんとStructって誰も使ってないんじゃないの……。
これの修正は1行修正でよかった
https://github.com/mruby/mruby/pull/3179/files
二つめ
Struct.new(:foo) { def initialize(*) self.foo end }.new
がSEGVするというもの。
ここでのinitializeは、新しく作られたStructからのインスタンスclassのinitializeで、
それを上書きしているわけだけども、上書きしないinitializeでself.foo
と呼べる準備をしており、
その準備をしないままだと、ありえない参照(StructはArrayとほぼ同じだ)をしてしまって落ちるようだった。
一つめの修正前でもself
は新しいStructのインスタンスclassなので、1つめとは別の問題。
一つめの修正をした上で
https://github.com/mruby/mruby/pull/3178/files
の修正をするとなおるっちゃなおるんだけど、実装が汚い。
なぜ汚いかというと、C言語は関数のスコープを「ファイルで閉じるスコープ」か、「実装内部だけで共有できるスコープ」か、「別のアプリケーションから参照できる公開されたスコープ」を作れる。 mrubyには「実装内部だけで共有できるスコープ」の部分がない(CRubyにはある)ので、 これをわざわざ作るのか、それともpublicなAPIとするしか共有するすべがない。
この辺を考えるのがめんどくさかったので、別の「ファイルで閉じるスコープ」の関数をコピペしてきた。これが微妙だ。
まあCRubyでいうalloc
にそうとうするやつなので公開してもいいような……でもmrubyではalloc
メソッドを作ってないから公開しないほうがいいような……。
というわけで、判断はmatzにまかせることにした。 margeされなくても、セグフォなのでいずれ誰かが何とかするでしょう。