Segfault on embedded ruby

Hi,
    This following problem is most likely due to my own
    misunderstandings, but I've not been able to resolve it after staring
    and scratching my head for quite a while. Here it is:

---------------Start code---------------

#include <ruby.h>
#include <iostream>
#include <string>
using namespace std;

void dontCrash(string s)
{
  VALUE test = rb_str_new2( s.c_str( ) );
  rb_gc_register_address(&test);
  rb_gc( ); // Test if gc gets corrupted
  rb_p( rb_str_new2(" stuff!!! ") );
  rb_p( test );
  rb_gc_unregister_address(&test);
}

int main ()
{
    ruby_init ();
    ruby_init_loadpath ();
    dontCrash("puts 'test'");
    ruby_finalize();
}

-------------- End code --------------------

The code (as reported by valgrind) always crashes on rb_gc( ).
Without the rb_gc( ), the code runs fine. It also crashes when
rb_register_address isn't called. This error has really got me
stumped, so any help is greatly appreciated.

Thanks,
-Godot

It doesn't crash for me.

What platform (os, ruby version, compiler, etc.) are you using?

Where in rb_gc() does the crash occur?

Does valgrind report anything out of the ordinary? (you'll probably want
to use a suppressions file such as the one in [ruby-talk:52065]).

Paul

Hi,

At Mon, 7 Jun 2004 04:33:40 +0900,
Godot wrote in [ruby-talk:102597]:

---------------Start code---------------

#include <ruby.h>
#include <iostream>
#include <string>
using namespace std;

  extern "C" void Init_stack(VALUE*);

void dontCrash(string s)
{
  VALUE test = rb_str_new2( s.c_str( ) );
  rb_gc_register_address(&test);
  rb_gc( ); // Test if gc gets corrupted
  rb_p( rb_str_new2(" stuff!!! ") );
  rb_p( test );
  rb_gc_unregister_address(&test);
}

int main ()
{
    ruby_init ();

      VALUE dummy;
      Init_stack(&dummy);

···

    ruby_init_loadpath ();
    dontCrash("puts 'test'");
    ruby_finalize();
}

--
Nobu Nakada

It doesn't crash for me.
What platform (os, ruby version, compiler, etc.) are you using?

That's strange,
Im using gentoo linux, ruby version emerged is 1.8.0-r6, compiling command
is 'g++ testruby.cpp -g -lruby18 -I<ruby path>'
Ive checked the version of ruby by printing out the defines
RUBY_VERSION and RUBY_RELEASE_DATE, and the library/include matches up.

Ive just tried it with ruby 1.8.1-r6 and this dumps as well.

Hmm... This is stranger, it works with ruby 1.6.8. Has garbage collection
management methods changed in between versions?

Where in rb_gc() does the crash occur?

The following is from gdb, valgrind gives many errors, all related to
rb_gc and rb_gc_mark_locations, but it is very verbose:

Program received signal SIGSEGV, Segmentation fault.
0x4007c683 in rb_gc_mark_locations () from /usr/lib/libruby18.so.1.8
(gdb) bt
#0 0x4007c683 in rb_gc_mark_locations () from /usr/lib/libruby18.so.1.8
#1 0x4007e156 in rb_gc () from /usr/lib/libruby18.so.1.8
#2 0x08048b18 in dontCrash(std::string) (s=Cannot access memory at address 0x0
) at testruby.cpp:12
#3 0x08048b8f in main () at testruby.cpp:22

Thanks again,
-Godot

ruby_init() calls Init_stack, so why should this be necessary?

Any why does it matter anyway whether the stack is properly initialized
jn this case, since the address is being registered with the garbage
collector? (and thus the object should be marked just fine)

Paul

···

On Tue, Jun 08, 2004 at 09:32:20AM +0900, nobu.nokada@softhome.net wrote:

> int main ()
> {
> ruby_init ();
      VALUE dummy;
      Init_stack(&dummy);
> ruby_init_loadpath ();
> dontCrash("puts 'test'");
> ruby_finalize();
> }

Hi,

At Tue, 8 Jun 2004 12:24:31 +0900,
Paul Brannan wrote in [ruby-talk:102734]:

> > int main ()
> > {
> > ruby_init ();
> VALUE dummy;
> Init_stack(&dummy);
> > ruby_init_loadpath ();
> > dontCrash("puts 'test'");
> > ruby_finalize();
> > }

ruby_init() calls Init_stack, so why should this be necessary?

To adjust the stack boundary.
The stack frame inside Init_stack() called from ruby_init()
would be placed at lower address than one of dontCrash() , so
that `test' in it would be outside the region of GC target.

···

--
Nobu Nakada

It works now :slight_smile: Thanks for all the help, I don't think I would've
come across that solution on my own. I'm still struggling to understand
why 1.6.8-r10 didn't crash while 1.8* did, however.

-Godot

···

On Tue, 08 Jun 2004 13:03:19 +0900, nobu.nokada wrote:

Hi,

At Tue, 8 Jun 2004 12:24:31 +0900,
Paul Brannan wrote in [ruby-talk:102734]:

> > int main ()
> > {
> > ruby_init ();
> VALUE dummy;
> Init_stack(&dummy);
> > ruby_init_loadpath ();
> > dontCrash("puts 'test'");
> > ruby_finalize();
> > }

ruby_init() calls Init_stack, so why should this be necessary?

To adjust the stack boundary.
The stack frame inside Init_stack() called from ruby_init()
would be placed at lower address than one of dontCrash() , so
that `test' in it would be outside the region of GC target.

But test was marked with rb_gc_register_address(). Shouldn't that
function work with addresses that are not on the stack?

Paul

···

On Tue, Jun 08, 2004 at 01:03:19PM +0900, nobu.nokada@softhome.net wrote:

> ruby_init() calls Init_stack, so why should this be necessary?

To adjust the stack boundary.
The stack frame inside Init_stack() called from ruby_init()
would be placed at lower address than one of dontCrash() , so
that `test' in it would be outside the region of GC target.

But test was marked with rb_gc_register_address(). Shouldn't that
function work with addresses that are not on the stack?

this is when ruby mark the stack that it has a problem, but the example
was badly written for an embedded application because it call ruby
function without any protection (rb_protect(), etc)

bad, bad, bad

Guy Decoux

Hi,

At Tue, 8 Jun 2004 23:40:36 +0900,
Paul Brannan wrote in [ruby-talk:102783]:

> > ruby_init() calls Init_stack, so why should this be necessary?
>
> To adjust the stack boundary.
> The stack frame inside Init_stack() called from ruby_init()
> would be placed at lower address than one of dontCrash() , so
> that `test' in it would be outside the region of GC target.

But test was marked with rb_gc_register_address(). Shouldn't that
function work with addresses that are not on the stack?

I've understood that [ruby-talk:102597] doesn't crash when
rb_gc_register_address() is called, wrong?

At Mon, 7 Jun 2004 04:33:40 +0900,
Godot wrote in [ruby-talk:102597]:

···

It also crashes when rb_register_address isn't called.

--
Nobu Nakada

Are you saying that I should rb_protect on rb_gc? Would that catch the
fault? That doesn't seem possible - but when it comes to ruby, Alot of
things that are seem impossible :slight_smile:

This was only an example illustrating a problem I was having on a larger
application. It was by no means meant to be more than that, but I do
appreciate the warning.

-Godot

···

On Wed, 09 Jun 2004 00:35:37 +0900, ts wrote:

> But test was marked with rb_gc_register_address(). Shouldn't that
> function work with addresses that are not on the stack?

this is when ruby mark the stack that it has a problem, but the example
was badly written for an embedded application because it call ruby
function without any protection (rb_protect(), etc)

bad, bad, bad

Guy Decoux

Maybe I read it wrong, but I thought it crashed regardless of whether it
was called.

Paul

···

On Wed, Jun 09, 2004 at 07:38:32AM +0900, nobu.nokada@softhome.net wrote:

I've understood that [ruby-talk:102597] doesn't crash when
rb_gc_register_address() is called, wrong?

Are you saying that I should rb_protect on rb_gc? Would that catch the
fault? That doesn't seem possible - but when it comes to ruby, Alot of
things that are seem impossible :slight_smile:

No, I was trying to say that your example was badly written. In an
embedded application, after the initialization phase you must *never* make
a call to a ruby function which is not protected with rb_protect(), or
what you want.

If ruby detect an error when it call a function, it will call longjmp()
and this can crash your application if you have not made a previous call
to rb_protect(), ...

If your application is well written, you don't need Init_stack()

Guy Decoux

That's correct, rb_gc_register_address doesn't prevent the crash, and the
more I read about Init_stack, the more I question why it even needs to be
called (although that does fix it).

This is from http://www.rubygarden.org/ruby?RubyApi/InitStack :

" If ruby_init() is not called from main(), you may need to use Init_stack
so Ruby knows the true bounds of the stack."

Now, either this wiki entry is only partially true, or ...?

Clueless as usual,
-Godot

···

On Thu, 10 Jun 2004 00:52:27 +0900, Paul Brannan wrote:

On Wed, Jun 09, 2004 at 07:38:32AM +0900, nobu.nokada@softhome.net wrote:

I've understood that [ruby-talk:102597] doesn't crash when
rb_gc_register_address() is called, wrong?

Maybe I read it wrong, but I thought it crashed regardless of whether it
was called.

Paul

Hi,

At Thu, 10 Jun 2004 04:13:41 +0900,
Godot wrote in [ruby-talk:102983]:

That's correct, rb_gc_register_address doesn't prevent the crash, and the
more I read about Init_stack, the more I question why it even needs to be
called (although that does fix it).

Hmmm, rb_gc_register_address should do. Something other might
go wrong.

This is from http://www.rubygarden.org/ruby?RubyApi/InitStack :

" If ruby_init() is not called from main(), you may need to use Init_stack
so Ruby knows the true bounds of the stack."

Now, either this wiki entry is only partially true, or ...?

It is difficult to say generally without assembler details,
because it is affected by compile option and so on.

···

--
Nobu Nakada

Hmmm, rb_gc_register_address should do. Something other might
go wrong.

yes, there is something else

It is difficult to say generally without assembler details,
because it is affected by compile option and so on.

you have found :slight_smile:

Now the original poster just need to write correctly its program.

Guy Decoux