日報 2016-07-22

exported from https://nippo.wikihub.io/@_ksss_/20160722124458

mruby本体に2つバグがあった。

一つめ

Struct.new(:a) do
  def foo
  end
end

とすると、fooメソッドはStruct.newで作られた新しいclassのメソッドになることを期待するが、 なんと、Structclassのメソッドになるというもの。ここでメソッドを定義してしまうと、全部の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されなくても、セグフォなのでいずれ誰かが何とかするでしょう。