exported form https://nippo.wikihub.io/@_ksss_/20160731140352
mrubyでのfork
のバグを直した。
https://github.com/iij/mruby-process/pull/7
引数に初期化されてない変数がブロック引数に渡されているので、 これをmruby側で参照すると死ぬ。
そもそもfork
にブロック引数はいらない。
mrubyのC側でブロック引数を無くす方法は2つ
mrb_yield(mrb, block, mrb_nil_value())
mrb_yield_argv(mrb, block, 0, NULL)
mrb_yield
とmrb_yield_argv
はほぼ同じ関数だが、ブロック引数の取り方に違いがある。
mrb_yield
はブロック引数を1つだけ指定できる。
mrb_yield_argv
は0〜いくらでも指定できる。
関数の中身もほぼ同じ
MRB_API mrb_value mrb_yield_argv(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv) { struct RProc *p = mrb_proc_ptr(b); return mrb_yield_with_class(mrb, b, argc, argv, p->env->stack[0], p->target_class); } MRB_API mrb_value mrb_yield(mrb_state *mrb, mrb_value b, mrb_value arg) { struct RProc *p = mrb_proc_ptr(b); return mrb_yield_with_class(mrb, b, 1, &arg, p->env->stack[0], p->target_class); }
https://github.com/mruby/mruby/blob/eb7422af581edff0dd4b1f8259598677b4d32793/src/vm.c#L657-L671
要約すると、mrb_yield
ではどんなにがんばっても引数を一つ与えていることになるので、意味的にはおかしい。
ブロック引数を0個にしたければ、mrb_yield_argv(mrb, block, 0, NULL)
を使うほうがヨサゲ。
どうやってこのバグを発見したかというと、単にコンパイルしたらclangがwarningで教えてくれただけだ。
つまりコンパイルさえすれば発見できる状態にあるが、2年近く放置されていたことになる。(ブロック引数なんかつけなきゃ問題ないので)
そしてこんなミミッチイ事を気にするのは、世界で僕ぐらいだったようである。
おしまい。