Bugs: Browse | Submit New | Admin

[#11859] GC will SIGSEGV if the free function of a data object

Date:
2007-06-26 16:57
Priority:
3
Submitted By:
Sylvain Joyeux (lapinot)
Assigned To:
Shyouhei Urabe (shyouhei)
Category:
Language / Runtime / Core Libraries
State:
Open
Platform:
 
Summary:
GC will SIGSEGV if the free function of a data object

Detailed description
The problem lies in the following scenario:

let assume that we're running the garbage collector. The stack is therefore

  #1 garbage_collect

Now, assume that the first object which should be freed is a T_DATA *and* its free function allocates a new object one
way or the other. We'll get something which look like

  #5 garbage_collect () at gc.c:1395
  #4 0x080774fe in rb_newobj () at gc.c:397
  #3 0x080e8fca in rb_int2inum ()
  #2 0x005140d3 in dlptr_free () from
/local/users/sjoyeux/system/i386-linux/ruby-1.8.6.svn/lib/ruby/1.8/i686-linux/dl.so
  #1 garbage_collect

In the second garbage_collect of the trace, during_gc is 1 and freelist is NULL. So, #garbage_collect calls add_heap
(gc.c:1395), whose elements are added to freelist.

Therein lies the problem: the assumption that freelist is touched by nobody but garbage_collect (assumption which underlies
the current garbage_collect implementation) is not kept. If the newly allocated heap is selected for deletion, some
of its elements are still in freelist *after* the end of garbage_collect and boom.

I'm not sure of what's the proper solution here. I don't think it is wise to assume that no Ruby object will ever be
allocated in free-functions, in which case one *must* assume that obj_free can allocate new objects. In that case, the
following patch should solve any problem:

 * it makes garbage_collect rebuild a freelist *locally* for each heap
 * it sweeps only the heaps that are present at the beginning of the sweep

That way, if new objects are allocated while freelist == NULL, a new heap is allocated and the new objects are allocated
in its slots. Since sweep will not see that heap, it will never try to free it. Moreover, it concatenates the heap-local
freelist to the global freelist each time

The performance hit is low, as it is an unlikely event (well, an unlikely event which appears systematically here, but
that's another story)

Note that the same problem (object allocation during sweep) can lead to other strange bugs: if we believe that a heap
should be deleted (because we found only unused elements in it), it is possible that the object allocation got one of
its elements from freelist in which case re-boom.


Add A Comment: Notepad

Please login


Followup

Message
Date: 2007-08-17 08:41
Sender: Sylvain Joyeux

Followup patch: fix DL so that it does not allocate memory 
in its free function anymore

http://rubyforge.org/tracker/index.php?func=detail&aid=13151&
amp;group_id=426&atid=1700
Date: 2007-06-27 09:33
Sender: Shyouhei Urabe

I've added [#11882] as this should be fixed in dl anyway.

And adding rb_bug seems appropriate to me.  I'll adopt it.
Date: 2007-06-27 06:06
Sender: Sylvain Joyeux

First, the attached patch does handle this particular 
problem.

Second, it is difficult to *not* do that in Ruby, since a 
lot of basic methods *do* allocate behind our back. The 
problem is not mine, it is in dlptr_free, which uses 
rb_int2inum which in turn allocates a new object.

I'm reopening the bug. Would you consider at least adding 
a rb_bug in rb_newobj when rb_newobj is called with the 
during_gc flag set ?

Do you want me to add a new bug for dlptr_free ?
Date: 2007-06-27 01:15
Sender: Shyouhei Urabe

> Now, assume that the first object which should be freed is
> a T_DATA *and* its free function allocates a new object

Don't do that.  Generally there are no safe way to do such a
job inside GC[1].  Instead use define_finalizer method of
ObjectSpace.  Finalizers are invoked in a safer way.

References:
[1] Hans Boehm: "Destructors, Finalizers, and
    Synchronization", POPL 2003, pp.262-272.

Attached Files:

Name Description Download
ruby_1.8.6_gcbug.patch Download

Changes:

Field Old Value Date By
resolution_idNone2007-06-27 01:15shyouhei
File Added2163: ruby_1.8.6_gcbug.patch2007-06-26 16:57lapinot