New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple calls to mrb_gc_(un)register for the same object #3160

Closed
dabroz opened this Issue May 27, 2016 · 0 comments

Comments

Projects
None yet
1 participant
@dabroz
Contributor

dabroz commented May 27, 2016

mrb_gc_register and mrb_gc_unregister make managing mruby objects on C side much easier. However, there is a problem if you call mrb_gc_register multiple times for the same object. The first call to mrb_gc_unregister will remove all registrations for this object.

I wrote a program illustrating this issue. Here we call a C function with two arguments, keeping only one of them from being collected. But if both arguments are actually the same object, the program will crash.

#include <mruby.h>
#include <mruby/proc.h>
#include <mruby/class.h>

mrb_value test;

mrb_value foo(mrb_state * mrb, mrb_value self)
{
  mrb_value a, b;
  mrb_get_args(mrb, "oo", &a, &b);
  mrb_gc_register(mrb, a);
  mrb_gc_register(mrb, b);
  // do something with a & b
  // a is no longer needed
  mrb_gc_unregister(mrb, a); // without this line the program will run correctly
  // only b will be kept
  test = b;
  return mrb_nil_value();
}

int main()
{
  mrb_state * mrb = mrb_open();
  RProc * proc = mrb_proc_new_cfunc(mrb, foo);
  mrb_define_method_raw(mrb, mrb->object_class, mrb_intern_cstr(mrb, "foo"), proc);
  mrb_load_string(mrb, "tap do ar = [1,2,3]; foo(ar, ar) end");
  mrb_garbage_collect(mrb);
  mrb_value state = mrb_funcall(mrb, test, "inspect", 0);
  mrb_funcall(mrb, mrb_top_self(mrb), "puts", 1, state);
  mrb_gc_unregister(mrb, test);
  mrb_close(mrb);
}

In theory I could ensure on C side that mrb_gc_register is only called once per object, but this is not as simple in general case.
So, could we modify behavior of mrb_gc_unregister so that it removes only one registration? Then it would be user responsibility to call mrb_gc_register and mrb_gc_unregister an equal number of times.

@matz matz closed this in 09b1185 Jun 10, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment