The segfault only occurs when the argument is a #to_proc'd Symbol, and the receiver needn't actually respond to the named method.
This bug was introduced in a rather large patch, and should almost certainly be fixed in one of the files modified therein. That said, I've discovered that removing the call to rb_block_clear_env_self() in sym_to_proc() prevents the segfault, as does setting env->env[0] to Qfalse rather than Qnil in rb_block_clear_env_self(). Neither of those is a proper fix, of course, but I hope this information may be of use to somebody more intimately familiar with Ruby's internals.
The prelude of check_cref() only checks whether obj is Qfalse; since rb_block_clear_env_self() uses Qnil, check_cref() continues by calling imemo_type() on Qnil, which eventually leads to Qnil being dereferenced and the interpreter crashing.
The fix is remarkably simple:
- if (obj == Qfalse) return NULL;
+ if (!RTEST(obj)) return NULL;
Thank you for reporting a bug and your detailed analysis.
They help me very much.
I am happy to have been of some assistance.
I believe `obj' should be Qfalse...
It's true that changing that Qnil to Qfalse is the "cleaner" fix this time around, but I think using RTEST() to check for both is slightly more future-proof. I've submitted a pull request which takes the latter approach, in addition to adding a couple of tests to ensure something like this will be caught in future. I shall take no offense if your much greater familiarity with YARV tells you that using Qfalse there is the better solution.
It's true that changing that Qnil to Qfalse is the "cleaner" fix this time around, but I think using RTEST() to check for both is slightly more future-proof. I've submitted a pull request which takes the latter approach, in addition to adding a couple of tests to ensure something like this will be caught in future. I shall take no offense if your much greater familiarity with YARV tells you that using Qfalse there is the better solution.
I changed data structures around these part to have NULL (== Qfalse). If not, then it should be a bug. Using RTEST() hides these bugs.
I will check your test and introduce to our tests.
I will also add some assertions in codes to check Qnil.