Bug #10466

rb_eval_string_wrap does not actually wrap in a module binding

Added by silverhammermba (Max Anselm) almost 6 years ago. Updated 10 months ago.

Target version:
ruby -v:
ruby 2.1.4p265 (2014-10-27 revision 48166) [x86_64-linux]


rb_eval_string_wrap says that it "evaluates the given string under a module binding in an isolated binding", but this isn't true.

Run the following:

#include <ruby.h>

int main(int argc, char* argv[])

    int state;
    rb_eval_string_protect("X = 2", &state);
    rb_eval_string_wrap("X = 3", &state);
    rb_eval_string_protect("puts X", &state);

    return ruby_cleanup(0);


outputs 2



eval:1: warning: already initialized constant X
eval:1: warning: previous definition of X was here

It looks like rb_eval_string_wrap tries to wrap it

    th->top_wrapper = rb_module_new();
    th->top_self = rb_obj_clone(rb_vm_top_self());
    rb_extend_object(th->top_self, th->top_wrapper);

But it ends up calling ruby_eval_string_from_file which uses rb_vm_top_self() as self, thus undoing the wrapping.

rb_load can perform similar wrapping, but there it works properly.


rb_eval_string_wrap_cref.patch (1.79 KB) rb_eval_string_wrap_cref.patch jeremyevans0 (Jeremy Evans), 07/23/2019 02:58 AM

Updated by retro (Josef Šimánek) almost 6 years ago

You can reproduce this without C code also. {X = 5} #=> #<Module:0x000000012186c0> {X = 5} #=> #<Module:0x00000001209da0> 
(irb):2: warning: already initialized constant X
(irb):1: warning: previous definition of X was here

And since rb_eval_string_wrap is really wrapping code into module, this works without warning:

#include <ruby.h>

int main(int argc, char* argv[])

  int state;
  rb_eval_string_wrap("self::Y = 'wrap'", &state);
  rb_eval_string_wrap("self::Y = 'wrap'", &state);

  return ruby_cleanup(0);

Updated by jeremyevans0 (Jeremy Evans) about 1 year ago

I agree this a bug. The documentation states for rb_eval_string_wrap that This is same as the binding for loaded libraries on "load('foo', true)", but that doesn't appear to be the case. load('foo', true) evaluates with an anonymous module in Module.nesting, but rb_eval_string_wrap uses an empty Module.nesting.

The attached patch should fix the issue by setting a cref, so that rb_eval_string_wrap evaluates the string with an anonymous module in Module.nesting. I'm not sure if this is the best way to fix it, and would appreciate if another committer could review this patch. Unfortunately, there are no tests for the rb_eval_string_wrap function and nothing internally seems to use this method.

Updated by ko1 (Koichi Sasada) about 1 year ago

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

Updated by jeremyevans (Jeremy Evans) 10 months ago

  • Status changed from Assigned to Closed

Applied in changeset git|e4db0443bcfc94f9183e8ea72fb4ab560aa005bf.

Make rb_eval_string_wrap specify a cref so constant setting works correctly

Fixes [Bug #10466]

Also available in: Atom PDF