Project

General

Profile

Actions

Bug #11409

closed

{instance,module}_eval(&:foo) segfaults since r51243.

Added by 0x0dea (D.E. Akers) almost 10 years ago. Updated almost 10 years ago.

Status:
Closed
Target version:
-
ruby -v:
ruby 2.3.0dev (2015-08-02 trunk 51469) [x86_64-linux]
Backport:
[ruby-core:70211]

Description

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.

Updated by 0x0dea (D.E. Akers) almost 10 years ago

Upon further investigation, I've discovered why replacing Qnil with Qfalse prevents the crash.

static rb_cref_t *
check_cref(VALUE obj, int can_be_svar)
{
    if (obj == Qfalse) return NULL;

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;

Updated by nobu (Nobuyoshi Nakada) almost 10 years ago

  • Status changed from Open to Assigned
  • Assignee set to ko1 (Koichi Sasada)

Updated by ko1 (Koichi Sasada) almost 10 years ago

Thank you for reporting a bug and your detailed analysis.
They help me very much.

In this case, I believe `obj' should be Qfalse or T_IMEMO objects. So that we clear by Qfalse intead of Qnil.

Reproducible code:

class Foo
end

Foo.instance_eval(&:p)

A patch:

Index: proc.c
===================================================================
--- proc.c	(revision 51472)
+++ proc.c	(working copy)
@@ -670,7 +670,7 @@ rb_block_clear_env_self(VALUE proc)
     rb_env_t *env;
     GetProcPtr(proc, po);
     GetEnvPtr(rb_vm_proc_envval(po), env);
-    env->env[0] = Qnil;
+    env->env[0] = Qfalse;
     return proc;
 }
 

Updated by 0x0dea (D.E. Akers) almost 10 years ago

Koichi Sasada wrote:

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.

Updated by ko1 (Koichi Sasada) almost 10 years ago

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.

Thaks,
Koichi

Actions #6

Updated by ko1 (Koichi Sasada) almost 10 years ago

  • Status changed from Assigned to Closed

Applied in changeset r51480.


Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0