Ruby and E.V.E. Paradox

Replying to the general content above...

Io developers are very smart and also very novel. They have managed to
reinvent a good portion of language ideas out there. This is a sign of
good levels of insanity. Sane people would probably fall in line and
do with the less than perfect tools available. Insane people take on
invisibly huge projects and responsibility to create things that some
people just haven't thought possible or realistic.

The result? Io is a great language that is combining a lot of healthy
features into a pretty usable package (co-routines, prototype object
system, message tree as objects as code -- hello lisp, etc... see
iolanguage.com or check out freenode's #io). It is regrettably
unstable though. I've fallen out of the active crowd, being so busy
with work, but last time I was involved it was mostly an unplanned
project with some rough ideas. I hope it has moved beyond project
management difficulties.

The use of darcs was actually one of the more key portions of the Io
community IMO. I have to admit I am biased though. I was one of the
people who originally suggested that darcs be used (there was a time
when there was nothing but rsync :S -- Steve is happily into the scm
thing now). What it let us do was experiment and detach things from
the main repository at any time and with anyone. Things like bikeshed
arguments quickly became show-me-a-darcs-patch. This really helped us
evolve things much faster than just a simple ML would have done.

The barrier to entry was also pretty high because of darcs and the use
of IRC over the ML for serious conversations. This meant you had to
put the time in to be heard. Is it fair? I don't know. It seems to
keep trolls out but does it prevent valid work? It probably is just a
trade off like anything. I've had success (great active collaboration)
and failure (a few bug fixes floating around that took over a week to
get applied when it isn't mentioned actively enough) with this system.

Haskell needs no major mention as it is pretty popular topic on social
networks like reddit. It is worth noting that it can be a pain to take
on such a large monster just to get an SCM installed. All I can say is
that I would rather have more stable projects using something other
than C (good bye seg-faults -- mostly).

As far as a good scm in Ruby... now there is something I would love to
see. I've honestly been thinking of porting Mercurial, as I have
mentioned many, many times. One other interesting option would be to
wrap git up into a ruby extension and then write some code with that.
Of course, like most of these stories go, I don't have time right
now... but if someone does, I would love to help out in smaller ways.

Brian.

···

On 1/16/07, benjohn@fysh.org <benjohn@fysh.org> wrote:

>
>> > What about Io? I haven't used either Io or Lua myself, but they
>> both
>> > seem to offer similar embedding-oriented features, and Io seems
>> like a
>> > more attractive language to work in.
>
> Io is, at this point in time, too immature, compared to Lua or Ruby.
> Their current "stable" release won't even compile.
> And, unfortunately, their developers are a tad insane and use darcs for
> revision control, which means you can spend almost an hour retrieving
> their current unstable release the first time you check it out.

:slight_smile: I thought Darks seemed pretty awesome when I looked, but very
annoying needing to get hold of ocaml or hascal, or what ever it was to
compile it up. Now, if it were written in Ruby...

Hey gga,

gga wrote:
> GD ha escrito:
>
>>This is an interesting idea but may be overkill for what I'm trying
>>to do.
>
> Well, I'd suggest you read swig docs and see if you still think is
> overkill for your project. Since you mentioned it is a game engine, I
> seriously doubt that it will be overkill.

I should clarify. My current usage of embedded scripting is fairly
basic. If I went the Ruby route, it would probably grow in scope in
time. Thus my original statement is only half correct. It is overkill
now, it might not be in the future.

I should also emphasise that the game engine handles the bulk of the
game stuff at present. The level scripts are mostly for tutorials or
small exceptions in level behaviour. Thus they are not terribly
demanding.

BUT...

As mentioned I'm weighing up expanding the scope of what the scripts
handle. Small baby steps first...

>> > VALUE result = rb_protect( wrap_callback, VALUE(&data), &error );
>>
>>You can do this!? Is this safe?
>
> Yes. Again, read ruby.h. It checks for this to be true... or ruby
> won't compile.

I remember a mention checking for the size of a number (long?) being
equivalent to a pointer, but not this specifically. Not saying it
isn't there, I just don't remember it.

>>Is there any authoritative source that
>>says: "directly casting a pointer to a VALUE is perfectly fine and
>>will continue to be supported".
>
> Besides me, you mean? I guess we have a trust issue, here :frowning:

Not a trust issue. Just wondering if this is a "well, it works for
me and it's good enough" or "this is the officially sanctioned way
to do it and it'd take a major release before it gets changed".

> Well, that relies on a feature of the C/C++ language. As long as you
> are using C ruby and we are dealing with 32/64-bit machines, it will
> hold true. Again, read ruby.h and config.h.
> Besides that, Matz has mentioned this is ok (search the list). His
> goal for VALUE was to have it be like void*, but clearer to users and
> keeping type safety. Unfortunately, C does not quite allow it to
> behave like a void* in all contexts, so sometimes you do need to cast
> it to void*.
> This is more or less a limitation of C/C++.
>
> If that's not enough for you, I'll try to see if I can convince the
> Pope to say something along those lines, but it might be tricky :slight_smile:

I haven't seen it in the list; but I haven't searched it- because
I didn't have any idea it could be the case at all until you
mentioned it. If it does have the Matz-seal-of-approval then that's
good to know- is definitely worth mentioning somewhere in the
official docs as it makes a HUGE difference knowing you can just
cast any pointer to a VALUE rather than having to create an
artificial array to hold it.

And if an official thumbs-up or thumbs-down came along, that would
probably be of enormous benefit to others embedding Ruby.

>>If so, VALUE can be used (effectively) in the same way as a void*,
>>so there is no need to convert everything into Ruby objects as
>>I had thought.
>
> Err... you weren't exposing each and every single little class in your
> code, were you? Ouch.
> That's not the idea, of course. The stuff you need to convert to Ruby
> is only the stuff you need your users to use in Ruby, as it stands to
> reason.

No way. No mass class exporting here. I'm actually content with declaring
classes directly in Ruby and doing any needed conversion myself (assuming
I can use opaque data structures too). I do want to expose a fair few
functions/methods from C++ to Ruby though, about twenty or so directly,
and many more indirectly. I need around a half dozen Ruby methods to
be visible to C++ for calling (the event and update methods I mentioned
previously).

>>I'll probably give it a shot for interest's sake. Looking closer at the
>>Python docs that don't seem as strong as first impressions suggest,
>>although there are some decent examples.
>>
>
> Well... what EXACTLY are you trying to achieve, Garret?

Garret is probably a lovely name to have. I also like Garnet as a
name. Unfortunately, around my birth I was named "Garth" and really
haven't seen much reason to change it since. :wink:

> You started
> the thread mentioning you WANTED to get away from Lua and use Ruby for
> your game engine.

Yes, that would be great.

This is the progression of thoughts on the issue:

- I was a touch frustrated with LUA, so I thought I'd weigh up replacements.
- After spotting information on Embedded Ruby and skimming through the source,
   I thought it looked promising. Weighing things up, I decided I could get
   additional benefits from scripting with Ruby beyond the current limited
   scripting use. Gave myself two days.
- I gave it a shot. Didn't turn out so well.
- Made a post detailing problems I've been having. Got a bunch of ideas.
   Plan to try many of them out to see which ideas work, and which don't.

The thing of note is that I'm more willing to sink a good chunk of
time into getting Ruby going ahead of other languages, because I *know*
Ruby is a good language to work with. But the time isn't open-ended. If
getting Ruby going would take 2 weeks and Python would take 2 hours,
my new scripting language is Python. If it was 2 days for Ruby and 2
*minutes* for Python, I'd go for Ruby. Basically Ruby gets extra grace
because I more fully understand what it can do.

> Personally, within the context of game engines, I must tell you, I
> think that's not such a good idea, as Lua is multi-thread safe today
> which is definitively something you do want in a game engine (and
> LuaJIT is probably *THE* fatest VM I have *EVER* seen for a non-static
> typed language).

The interface to the script will always run in a single thread with
my software, so threading issues aren't a huge concern. Power of
expression is very useful though, hence looking at Ruby.

> As such, I warned you before-hand that neither Python nor Ruby are
> thread safe.

Yep.

> You did mention you liked Ruby's syntax better than anything else and
> you did not care about multi-threading, so I kept helping you with
> ruby.

Yes.

> You mentioned you had difficulties embedding Ruby, and I gave you
> pointers for you to read on. You did not understand how to use a
> couple of functions, and I pointed to you the right stuff you should be
> using.

Indeed, thanks.

> You posted some code that crashed on you, and I gave you similar
> working code that works reliably, with compiling instructions to boot.
> You questioned whether my code was valid, which means you probably have
> not tried running it.
> You have also not followed my advice of looking at SWIG and, instead,
> now you want to look at Python (!?). Are you pulling my chain?

I work two jobs. Both involve using Ruby. :slight_smile: Unfortunately only one
involves Embedded Ruby. Factoring in any time difference, guess which
of the two jobs I've been at recently. :wink:

I'll be back and able to do more Embedded Ruby stuff in under 24 hours.
I fully intend to pull in the sample code fragments you've been mentioning
and see how they work with my code. As I mentioned, the SWIG suggestion
is good, and this is also something I will be playing with. Even if I
don't use SWIG, no doubt I can learn much from its output.

I have not questioned your code, just indicated that I haven't been
able to run it yet. My development and net access are on two
completely different non-connected machines, and my present Embedded
Ruby code is a mess- I've been experimenting to find ways around the
current problems I am experiencing. I can't just drop your fixes in,
even if they are 100% perfect; my present Embedded Ruby code is still
a mess!

As for Python, this is what I used quite some time ago. Suddenly one
day a beautiful creature named Ruby came through and swept me off my
feet. Anyway, I don't hate Python, I just like Ruby much more. So
it is still a valid choice for embedding target from my POV. Given
a choice, Ruby is the one for me. But I'm having real trouble with it.

So I'll probably have a play around. I'll see how I go with the new
Ruby knowledge I've picked up here, probably give Python a shot, try
out Scheme, and even give LUA another look. In each case there is
scope for improvement to my code. I do feel the greatest benefit will
come from Ruby though- just a matter of effort versus reward.

I'm basically going through an improvement/experimentation phase with
my software at the moment. Hence my desire to try a few things out.
I'm looking to spend some time now to get payoffs through the next
year.

> If you DO want to use Python for wrapping a library, and you are
> familiar with C++ template use, I suggest using boost::python and Py++.
> It is slightly more efficient than SWIG, albeit it can be hard to
> debug if you are not familiar with templates.
>
> If you don't like templates (like myself), I would ALSO recommend you
> learn and use SWIG for embedding Python.

Yep, SWIG seems like a good thing to examine regardless.

I didn't know Boost had some Python gear. I'm using various bits of
Boost already. Could be interesting.

> Is there any reason why you are avoiding SWIG and not even looking at
> the documentation I pointed you to?

As above, lack of time for the next 24 hours. Then I get a few hours,
sleep, and then most of a day. Trust me, I'm not yet done with this
stuff! I've been given a bunch of useful ideas by various people on
this list (including yourself) and I feel I owe them the courtesy
of trying out some of the suggestions. It all takes time though.

> In case you did not find it, it's
> here, btw:
> http://www.swig.org/Doc1.3/Ruby.html#Ruby (read: memory management
> section)
> http://www.swig.org/Doc1.3/Contents.html#Contents
>
> You will learn quite a lot about embedding stuff from reading it. My
> guess is that the problems you are having with Ruby and perhaps Lua
> might be because you are not too familiar with the subtleties that can
> arise from exposing classes to scripting languages. SWIG does a really
> good job of explaining that (best thing I've seen yet) and has working
> and relatively well tested code in about 20+ languages.
>
> The good thing about SWIG is that you can actually use Lua (which you
> mentioned you know well already)

My LUA knowledge is "sufficient" only- I wouldn't say I know it well.
I know Ruby well, and Embedded Ruby, barely at all. :wink:

> and expose one or two classes that way
> first. Then, you should be able to easily port that code to ruby, by
> just changing just a couple of swig files (if any).
> Also, if you end up dropping Ruby at some point in time, you should be
> able to again port your code easily to whatever other language you
> fancy.

Bringing SWIG into my project seems an interesting idea. At this point
I'd rather learn from it, but perhaps it would be useful to use the
tool itself directly.

Re the mention of classes, I barely need to share classes at all. As
long as I can pass an opaque pointer to the game class through Ruby
and get it back at the other end, and call functions/methods from
C++ to Ruby to C++, I'm 98% of the way there.

The remaining 2% just involves some initialisation that involves
creating some Ruby objects on the C++ side and having them available
to manipulate with the functions and methods.

>>(*) - Technically I _did_ in a couple of hours, but it wasn't stable and
>>crashed randomly, so I tried to figure out what was going wrong. No luck.
>
> Well, if you've wrapped a class or two and they are crashing, your best
> bet is posting the code to them to get help. Otherwise, it is unlikely
> anyone will be able to help you out much.

I've got a few snippets I can grab; the main things I'm still
uncertain of are relating to protecting objects etc from the
GC, and how to indicate they are free to clean. I'll post them
as soon as I can.

> Also, it will be hard for anyone to write better docs, if nobody knows
> what exactly are you having difficulties with.

Indeed. I've indicated (in length) some of the issues I've been having,
but you are right, I am light on the specifics.

I'd like to minimise the rest of the code as best I can to produce a
bearable test-case that causes problems because as it stands there is
too much non-Embedded-Ruby code for me to sensibly post (and I'm a bit
touchy about some of the non-Ruby code!).

My current code crashes (in the second rb_gc) with something of the form:

void a()
{
   init_ruby();
   rb_gc();
}

void b()
{
   rb_gc();
}

int main(int argc, char **argv)
{
   a();
   b();
}

And starts working when I reorder like this:

void a()
{
   rb_gc();
}

void b()
{
   rb_gc();
}

int main(int argc, char **argv)
{
   init_ruby();
   a();
   b();
}

This triggered my question about whether Ruby makes assumptions about the
stack and if it needs to be called in a persistent frame (not this is not
the case in the first sequence). The actual code of course is much more
complex; we've got calls that cross library boundaries and a few more
stack layers in-between. As mentioned, I'd like to reduce the problem down
to something simpler. But given the simplified code above, could you see
a potential crash from running it like that? If so, that is something
potentially worth mentioning.

Reducing the code down further to a more minimalistic form may expose a
problem on my side as well. If not, I'll have something sensible to
provide as a "is something wrong with this code" example.

>>I would suggest that a good place for these little tips and tricks that keep coming up
>>would be somewhere near the official documentation, so that the next
>>person who comes along to play with embedded Ruby can start off
>>slightly further ahead than I did.
>>
>
> Sure. Feel free to write them up somewhere. In case it was not clear,
> any code or snippet of code I posted in this thread is public-domain.

The best I could manage is to collate your thoughts, as is quite apparent
my Embedded Ruby knowledge is extremely limited. I am completely and
utterly unqualified to write about Embedded Ruby! :wink: There are topics
I could write on, but when restricted to Ruby I could at best offer
tutorials to new users. The existing ones are already pretty good.

Now it's 11:30pm, so I'm off to bed. Hopefully I'll be back to embedded
language experimentation next evening after my other job.

Garth

Brian Mitchell wrote:

As far as a good scm in Ruby... now there is something I would love to
see. I've honestly been thinking of porting Mercurial, as I have
mentioned many, many times. One other interesting option would be to
wrap git up into a ruby extension and then write some code with that.
Of course, like most of these stories go, I don't have time right
now... but if someone does, I would love to help out in smaller ways.

Brian.

Bah! A new FAQ -- we've done editors, IDEs and GUI Toolkits, so let's have a "what's the best version control system for Ruby" contest now. :slight_smile:

But seriously, folks, why does a version control system need to be written in any particular language? Shouldn't Rubyists focus on tools that increase productivity in Ruby, like tools that deal with the specifics of Ruby syntax and semantics, rather than trying to re-invent a version control system, an editor, an IDE, etc.?

Speaking of which, I decided to have a bake-off between KDevelop and Komodo 4 Beta for a Ruby IDE. I think in the end KDevelop is going to win, because it does more languages than Komodo, free is a very good price, and I don't need Windows, MacOS or Solaris compatibility. But Komodo 4 is a pretty good tool from what I've seen, and if I have to do a lot of Perl development in my "day job" on Windows/ActiveState Perl, I'll probably ask for a copy and take the Ruby IDE as a "bonus". KDevelop has some nice integration with QtRuby as well, and I *think* it's possible to develop QtRuby (QT4) on KDevelop that can be deployed on a Windows system. Komodo has some nice integration with Tk. :slight_smile:

···

--
M. Edward (Ed) Borasky, FBG, AB, PTA, PGS, MS, MNLP, NST, ACMC(P)
http://borasky-research.blogspot.com/

If God had meant for carrots to be eaten cooked, He would have given rabbits fire.

My current code crashes (in the second rb_gc) with something of the form:

Post your ACTUAL code that crashes. init_ruby() does not exist as an
api call in ruby, so we'll need to see source to that.
If what you meant was something like this:

/**
* @file embed.cpp
* @author gga
* @date Wed Jan 17 11:40:27 2007

···

*
* g++ -I/usr/lib/ruby/1.8/x86_64-linux embed.cpp -o embed -lruby1.8
*
*/

#include <ruby.h>

void a()
{
   ruby_init();
   rb_gc();
}

void b()
{
   rb_gc();
}

int main(int argc, char **argv)
{
   a();
   b();
   return 0;
}

I can tell you it works fine for me, so if that crashes for you may
have a broken ruby or some .so dependency issue on your machine.

Why not. Not a single word in that told you to go out of your way to
use it. Thanks goes wholly to OSS. Some of us like to innovate rather
than sit around. I don't think I would be productive trying to modify
Subversion's code base to do what I want out of an SCM tool. It just
comes down to the fact that I am better with Ruby.

sarcasm do

For that, why are we even speaking multiple of anything? Why don't we
all use the same language, the same OS, the same hardware... and while
we are at it, we can have the same attitude ideas and personalities.

end

Brian.

···

On 1/16/07, M. Edward (Ed) Borasky <znmeb@cesmail.net> wrote:

Brian Mitchell wrote:
> As far as a good scm in Ruby... now there is something I would love to
> see. I've honestly been thinking of porting Mercurial, as I have
> mentioned many, many times. One other interesting option would be to
> wrap git up into a ruby extension and then write some code with that.
> Of course, like most of these stories go, I don't have time right
> now... but if someone does, I would love to help out in smaller ways.
>
> Brian.
Bah! A new FAQ -- we've done editors, IDEs and GUI Toolkits, so let's
have a "what's the best version control system for Ruby" contest now. :slight_smile:

But seriously, folks, why does a version control system need to be
written in any particular language? Shouldn't Rubyists focus on tools
that increase productivity in Ruby, like tools that deal with the
specifics of Ruby syntax and semantics, rather than trying to re-invent
a version control system, an editor, an IDE, etc.?

Speaking of which, I decided to have a bake-off between KDevelop and
Komodo 4 Beta for a Ruby IDE. I think in the end KDevelop is going to
win, because it does more languages than Komodo, free is a very good
price, and I don't need Windows, MacOS or Solaris compatibility. But
Komodo 4 is a pretty good tool from what I've seen, and if I have to do
a lot of Perl development in my "day job" on Windows/ActiveState Perl,
I'll probably ask for a copy and take the Ruby IDE as a "bonus".
KDevelop has some nice integration with QtRuby as well, and I *think*
it's possible to develop QtRuby (QT4) on KDevelop that can be deployed
on a Windows system. Komodo has some nice integration with Tk. :slight_smile:
>

Hey gga,

gga wrote:

My current code crashes (in the second rb_gc) with something of the form:

Post your ACTUAL code that crashes.

Of course. Reasons why I haven't done this yet in my previous
post. Will post when I can get a reasonably minimal set with
problems.

init_ruby() does not exist as an
api call in ruby, so we'll need to see source to that.

My mistake, init_ruby should be ruby_init, it was late and
I was going from memory.

#include <ruby.h>

void a()
{
   ruby_init();
   rb_gc();
}

void b()
{
   rb_gc();
}

int main(int argc, char **argv)
{
   a();
   b();
   return 0;
}

I can tell you it works fine for me,

Okay, that's good news. I have a working side and a failing side
to work from now, let's find where they meet in the middle.

Garth

Hey everyone,

Tracking down this problem was NOT easy, but here we go.

I created a small program that made some basic embedded API calls, mirroring
the functionality I was trying to add into E.V.E. Paradox. It worked
perfectly, suggesting the problem was not Ruby.

I then took the existing E.V.E. Paradox code and tried to add traces and extra
calls in to find the problem. Basically I added calls that repeatedly called
rb_funcall at various points. Basically at various points in my code it was
possible to call rb_funcall successfully, branch off into other code, then
make the exact same call again and have it crash.

Tracking it down further was a nightmare. Basically the point of the bug moved
as extra calls were added to perform traces and call rb_funcall. The
probability of a crash tended towards zero in any region of code as more
traces and calls were added. Thus as I got closer to the problem, it would
move somewhere else. It suggested some kind of stack dependency from Ruby or
corruption being caused in my code or the libraries I was using.

For a while I thought the cause was a poor interaction between Ruby and
freetype, as it most commonly crashed after calls relating to font
manipulation when inside that library.

However, I was finally able to create some isolated code that crashed with
high frequency. So it's not E.V.E. Paradox or freetype. I did this by writing
a function that simulates API calls being made in the context of a larger
program through controlled recursive calls and alloca. Basically the call
wraps various Ruby interactions inside and alongside repeated adding and
removing of stack frames through nested calls.

This code is included below (NB: Linux only).

Interestingly enough, I haven't seen it crash yet when profiling is disabled.
Only when it is enabled. Is there some negative interaction between the
profiling code in the gcc 4.* series and Ruby? Anyway, I thought it
interesting.

As for running the code, simply build it with make (you may need to fix the
path to Ruby) and run it in one of these four modes:

./foo 0

This will run a simple set of code that outputs an series of annoying
traces. No stack trickery is done. It works.

./foo 1

This will run a simple set of code that calls an embedded Ruby script,
which calls a callback in the code. It works.

./foo 2

This performs the same traces but uses "messy" to fire them off within
differing stack contexts. It is slow, but works.

./foo 3

This performs the same set of Ruby calls, but uses "messy" to fire them off
within differing stack contexts. It is slow, and eventually crashes.

Thus Embedded Ruby works fine in simple code, but put it in the context of
a larger body and it has the potential to crash.

At some point I will have a play around with different versions of Ruby to
see if they also trigger this crash, and if I can work around the problem
this way.

Anyway, what I'd like to ask of the ordinary Ruby users like me and of the
Ruby Gods is:

- Does the test code look okay? Did I make any mistakes? I'm only human, and
   the crash test isn't trivial.
- Does "./foo 3" also crash on your machine? Or is it just mine?
- Are there any Ruby Gods for whom the code crashes with the skill to
   diagnose the problem with Ruby itself? I fear this may be beyond me (but
   I'll be giving it a shot).

Other info:

- The rest of E.V.E. Paradox and the multiple external libraries work fine
   with profiling enabled. *IF* it is a compiler/profiler bug, it affects Ruby
   *only*.
- My development machine is pretty stable, quite able to perform days-long
   tests and compiles consistently- although I have to admit the DVD tray
   mechanism is a bit touchy. This isn't a memory or solar flare thing.
- I use alloca to simulate calls to functions with different stack depth
   requirements. If you object to alloca, please note that mode 2 of the
   test program works perfectly fine- this is heavy alloca use without Ruby
   calls. It crashes only when we add Ruby calls to the mix.
- As noted, I think it only happens if profiling is enabled. I can't guarantee
   it doesn't crash without, I just haven't seen it do so.
- "Don't enable profiling" isn't really an acceptable workaround when it
   works fine for the rest of the large body of code and external libraries
   and my development build includes it by default. I really don't want to
   have to rebuild the whole project when I'm after timing information...
   Besides, "does not work with profiling" appears to be a significant bug.

Anyway, this is enormously frustrating, as after all of this struggle I've
been able to put together a proof-of-concept that I *can* use the embedded
Ruby interface in my code, but I cannot actually keep it due to the
stability issues. :(:frowning:

I am available for questions, further information, and testing should anyone
with the requisite knowledge to diagnose the problem need my input. Please
feel free to drop me an email if I can help (see the contact page at
www.entropicsoftware.com for my direct email).

Further detailed information below. Apologies in advance for the huge post,
but there is a lot of relevant detail to convey.

Garth

···

-------------

============================================================================
== Contents of foo.cpp:

#include <ruby.h>

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>

#define MYRAND(r) (rand()%r)

using namespace std;

static VALUE obj;

typedef void (MessyFunc)(void *);

typedef VALUE (*RubyGenericFunc)(...);

static int mode = 0;
static bool use_messy;
static bool use_ruby;

static VALUE RubyP(int argc, VALUE *argv, VALUE self)
{
   VALUE str = rb_str_new("", 0);
   for (int i=0; i<argc; i++)
   {
     if (i > 0)
       rb_str_cat(str, ", ", 2);
     rb_str_concat(str, rb_inspect(argv[i]));
   }
   cerr << "Ruby P: " << RSTRING(str)->ptr << "\n";
   return Qnil;
}

static VALUE RubySafeGCX(VALUE a)
{
   rb_gc();
   return Qnil;
}

static VALUE RubySafeGC()
{
   int status;
   VALUE rv = rb_protect(RubySafeGCX, Qnil, &status);
   if (status)
   {
     VALUE einfo = rb_obj_as_string(ruby_errinfo);
     cerr << "Ruby reported error: " << status
          << " " << RSTRING(einfo)->ptr << ".\n";
   }
   return rv;
}

static void RubySafeGCZ(void *t)
{
   RubySafeGC();
}

static void InitRuby(void *t)
{
   ruby_init();
   RubySafeGC();
}

static void InitRuby2(void *t)
{
   rb_define_global_function("p", (RubyGenericFunc)RubyP, -1);
}

static void InitRuby3(void *t)
{
   int status;
   rb_eval_string_protect(
     "class Foo\n"
     " def initialize(z)\n"
     " @a = z\n"
     " end\n"
     " def update(v)\n"
     " p(v)\n"
     " end\n"
     "end\n"
     , &status);
   if (status)
   {
     VALUE einfo = rb_obj_as_string(ruby_errinfo);
     cerr << "Ruby reported error: " << status
          << " " << RSTRING(einfo)->ptr << ".\n";
   }
}

static void InitRuby4(void *t)
{
   VALUE c_foo = rb_const_get(rb_cObject, rb_intern("Foo"));
   VALUE c_bar = INT2NUM(555);
   obj = rb_funcall(c_foo, rb_intern("new"), 1, c_bar);
}

static void update(int i)
{
   rb_funcall(obj, rb_intern("update"), 1, INT2NUM(i));
}

static void update2(void *t)
{
   update(*((int *)t));
}

static void badger(int i)
{
   cerr << (((i % 6) < 4) ? "Badger " : "Mushroom") << " " << i << "\n";
}

static void badger2(void *t)
{
   badger(*((int *)t));
}

static void Nothing(void *t)
{
}

static void messy2(MessyFunc t, void *td, int depth, bool &done)
{
   // Add random crap to the stack that will be checked and reclaimed at
   // the end.
   int ss = MYRAND(40)*4+8;
   int mv = MYRAND(256);
   unsigned char *data = (unsigned char *)alloca(ss);
   memset(data, mv, ss);

   for (int i=0; i<ss; i++)
   {
     if (data[i] != mv)
     {
       cerr << "Stack corrupted immediately.\n";
       cerr << (int)(data[i]) << " " << mv << "\n";
       exit(1);
     }
   }

   //cerr << "D: " << depth << "\n";
   if (depth < 0)
     return;

   for (int i=0; i<(MYRAND(3)+1); i++)
     messy2(t, td, depth-1, done);
   if ((depth == 0) && (!done) && (t))
   {
     (*t)(td);
     done = true;
   }
   for (int i=0; i<(MYRAND(3)+1); i++)
     messy2(t, td, depth-1, done);

   for (int i=0; i<ss; i++)
     if (data[i] != mv)
     {
       cerr << "Stack was corrupted.\n";
       cerr << (int)(data[i]) << " " << mv << "\n";
       exit(1);
     }
}

void messy(MessyFunc t, void *td = NULL)
{
   int depth = MYRAND(5)+6;
   bool done = false;

   if (use_messy)
     messy2(t, td, depth, done);
   else
   {
     if (t)
       (*t)(td);
   }
}

int main(int argc, char *argv[])
{
   if (argc != 2)
   {
     cerr << "Usage: foo <mode>\n";
     cerr << " 0 - Simple Badger.\n";
     cerr << " 1 - Simple Ruby.\n";
     cerr << " 2 - Badger with stack use.\n";
     cerr << " 3 - Ruby with stack use.\n";
     exit(1);
   }
   mode = atoi(argv[1]);
   use_messy = (mode & 2);
   use_ruby = (mode & 1);

   cerr << "Mode " << mode
        << ". Messy " << (use_messy ? "enabled" : "disabled")
        << ". Ruby " << (use_ruby ? "enabled" : "disabled")
        << ".\n";

   cerr << "Empty test...\n";
   messy(Nothing);

   // Initialise.
   cerr << "Initialising...\n";
   if (use_ruby)
   {
     messy(InitRuby);
     messy(RubySafeGCZ);
     messy(InitRuby2);
     messy(RubySafeGCZ);
     messy(InitRuby3);
     messy(RubySafeGCZ);
     messy(InitRuby4);
     messy(RubySafeGCZ);
   }

   // Test over and over.
   cerr << "Thrashing...\n";
   for (int i=0; i<10000; i++)
   {
     if (use_ruby)
     {
       messy(RubySafeGCZ);
       messy(update2, &i);
       messy(RubySafeGCZ);
     }
     else
       messy(badger2, &i);
   }

   // Clean up.
   cerr << "Done thrashing.\n";
   if (use_ruby)
   {
     messy(RubySafeGCZ);
   }

   cerr << "Everything was okay.\n";
}

============================================================================
== Contents of Makefile:

foo: foo.o
  g++ -Wall -pg -g -o foo foo.o -L/packages/ruby/lib -lruby

foo.o: foo.cpp
  g++ -Wall -pg -g -c -o foo.o foo.cpp -I/packages/ruby/lib/ruby/1.8/i686-linux

clean:
  rm -f foo.o foo *~

============================================================================
== Extra Notes

> uname -a
Linux notimportant 2.6.18-1.2798.fc6 #1 SMP Mon Oct 16 14:54:20 EDT 2006 i686 athlon i386 GNU/Linux

> cat /etc/fedora-release
Fedora Core release 6 (Zod)

> ldd foo | grep ruby
         libruby.so.1.8 => /packages/ruby/lib/libruby.so.1.8 (0x00110000)

> ls -la /packages/ruby/lib/libruby.so*
lrwxrwxrwx 1 root root 16 Jan 15 23:19 /packages/ruby/lib/libruby.so -> libruby.so.1.8.5
lrwxrwxrwx 1 root root 16 Jan 15 23:19 /packages/ruby/lib/libruby.so.1.8 -> libruby.so.1.8.5
-rwxr-xr-x 1 root root 1897472 Jan 15 23:18 /packages/ruby/lib/libruby.so.1.8.5

> ls -la /usr/lib/libruby.so*
ls: No match.

> echo $LD_LIBRARY_PATH | grep /packages/ruby/lib | wc -l
1

> g++ -v
Using built-in specs.
Target: i386-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-libgcj-multifile --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre --with-cpu=generic --host=i386-redhat-linux
Thread model: posix
gcc version 4.1.1 20061011 (Red Hat 4.1.1-30)

> ruby -v
ruby 1.8.5 (2006-12-25 patchlevel 12) [i686-linux]

##########################

# Ruby was built from source with:

tar xfz ../ruby-1.8.5-p12.tar.gz
cd ruby-1.8.5-p12 || exit 1
./configure --enable-shared --prefix=/packages/ruby-1.8.5-p12 || exit 1
make || exit 1
make install || exit 1

# Also note:

> ls -lad /packages/ruby
lrwxrwxrwx 1 root root 14 Jan 15 23:19 /packages/ruby -> ruby-1.8.5-p12

##########################

> make
g++ -Wall -pg -g -c -o foo.o foo.cpp -I/packages/ruby/lib/ruby/1.8/i686-linux
g++ -Wall -pg -g -o foo foo.o -L/packages/ruby/lib -lruby

> ./foo 3

Mode 3. Messy enabled. Ruby enabled.
Empty test...
Initialising...
Thrashing...
Ruby P: 0
Ruby P: 1
[ ... lines removed ... ]
Ruby P: 124
Ruby P: 125
(eval):7: [BUG] Segmentation fault
ruby 1.8.5 (2006-12-25) [i686-linux]

Abort

##########################

gdb ./foo
GNU gdb Red Hat Linux (6.5-8.fc6rh)
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".

(gdb) set args 3
(gdb) run
Starting program: /home/garthy/dev/test/ruby/foo 3
Mode 3. Messy enabled. Ruby enabled.
Empty test...
Initialising...
Thrashing...
Ruby P: 0
Ruby P: 1
[ ... lines removed ... ]
Ruby P: 124
Ruby P: 125

Program received signal SIGSEGV, Segmentation fault.
0x004935fe in st_lookup (table=0x0, key=6905, value=0xbfd83c08) at st.c:250
250 hash_val = do_hash(key, table);
Current language: auto; currently c
(gdb) bt
#0 0x004935fe in st_lookup (table=0x0, key=6905, value=0xbfd83c08) at st.c:250
#1 0x0042aa7c in search_method (klass=3085892280, id=6905, origin=0xbfd83c38)
     at eval.c:480
#2 0x0042aadd in rb_get_method_body (klassp=0xbfd83c68, idp=0xbfd83c74,
     noexp=0xbfd83c78) at eval.c:501
#3 0x00434263 in rb_call (klass=3085892280, recv=3085892320, mid=6905,
     argc=1, argv=0xbfd83ca0, scope=1) at eval.c:6024
#4 0x00434866 in vafuncall (recv=3085892320, mid=6905, n=1, ar=0xbfd83d04)
     at eval.c:6125
#5 0x004349d0 in rb_funcall (recv=3085892320, mid=6905, n=1) at eval.c:6142
#6 0x08048ce3 in update (i=126) at foo.cpp:101
#7 0x08048d02 in update2 (t=0xbfd8440c) at foo.cpp:106
#8 0x080491bd in messy2 (t=0x8048cea <update2>, td=0xbfd8440c, depth=0,
     done=@0xbfd843cf) at foo.cpp:150
#9 0x08049151 in messy2 (t=0x8048cea <update2>, td=0xbfd8440c, depth=1,
     done=@0xbfd843cf) at foo.cpp:147
#10 0x08049151 in messy2 (t=0x8048cea <update2>, td=0xbfd8440c, depth=2,
     done=@0xbfd843cf) at foo.cpp:147
#11 0x08049151 in messy2 (t=0x8048cea <update2>, td=0xbfd8440c, depth=3,
     done=@0xbfd843cf) at foo.cpp:147
#12 0x08049151 in messy2 (t=0x8048cea <update2>, td=0xbfd8440c, depth=4,
     done=@0xbfd843cf) at foo.cpp:147
#13 0x08049151 in messy2 (t=0x8048cea <update2>, td=0xbfd8440c, depth=5,
     done=@0xbfd843cf) at foo.cpp:147
#14 0x08049151 in messy2 (t=0x8048cea <update2>, td=0xbfd8440c, depth=6,
     done=@0xbfd843cf) at foo.cpp:147
#15 0x08049151 in messy2 (t=0x8048cea <update2>, td=0xbfd8440c, depth=7,
     done=@0xbfd843cf) at foo.cpp:147
#16 0x0804934b in messy (t=0x8048cea <update2>, td=0xbfd8440c) at foo.cpp:171
#17 0x08049611 in main (argc=2, argv=0xbfd844b4) at foo.cpp:223

Brian Mitchell wrote:

Why not. Not a single word in that told you to go out of your way to
use it. Thanks goes wholly to OSS. Some of us like to innovate rather
than sit around. I don't think I would be productive trying to modify
Subversion's code base to do what I want out of an SCM tool. It just
comes down to the fact that I am better with Ruby.

Yes ... I understand the need to create and need to innovate as much as anyone. However, there are lots of worthwhile projects that are begging for developers to enhance and maintain them while other developers are re-inventing wheels, levers, inclined planes and pulleys. And there's even more "worthwhile" open source software that is languishing because only other programmers can use it!

Now in the specific case of version control systems, the main reason there seem to be so many of them is that different project management schemes have different requirements, and only the heavy-duty industrial strength (and expensive) ones like ClearCase have any hope of covering lots of those bases. And before you go beating up on ClearCase, I don't happen to be a big fan of it, I know it has warts, but it's what's mandated in a lot of places.

CVS is still "good enough" for lots of SCM users, and between CVS and SVN, there's not much need for more innovation as far as I'm concerned. One of the big principles of "agile" and "pragmatic" development is YAGNI -- You Ain't Gonna Need It!

sarcasm do

For that, why are we even speaking multiple of anything? Why don't we
all use the same language, the same OS, the same hardware... and while
we are at it, we can have the same attitude ideas and personalities.

end

Well, actually, we pretty much do all use the same language -- C and dialects of C -- and we pretty much all do use the same hardware -- x86 and x86-64. We pretty much all have a "File" menu in the upper left corner, we pretty much all have a mouse and a keyboard and a color graphical display, we pretty much all talk to each other using IPV4 and dozens of other standard protocols, etc., etc. Innovations need to be *compelling* to get someone to use something else.

I don't really think of Ruby as innovative -- one of the charming things about Ruby is that it is a collection of good ideas that have stood the test of time. Regular expressions, classes, objects and methods, dynamic "typing", flexible syntax, "it's always run time", continuations, arbitrary precision integer arithmetic, flexible arrays and hashes --- these are all wheels that Ruby didn't re-invent!

···

--
M. Edward (Ed) Borasky, FBG, AB, PTA, PGS, MS, MNLP, NST, ACMC(P)
http://borasky-research.blogspot.com/

If God had meant for carrots to be eaten cooked, He would have given rabbits fire.

An additional note: I've since been running the code provided for several hours in mode 3 (Ruby and messy stack frame), built _without_ profiling information (ie. without "-pg") and it has been running without failure for over 2600 iterations. If I rebuild with "-pg" the problem generally strikes in the 100-200 iterations range. Thus it is probably a fair assumption that the problem arises only when profiling is enabled. I'll leave it running for a bit longer and will post any failures should they occur.

Garth

Brian Mitchell wrote:
> Why not. Not a single word in that told you to go out of your way to
> use it. Thanks goes wholly to OSS. Some of us like to innovate rather
> than sit around. I don't think I would be productive trying to modify
> Subversion's code base to do what I want out of an SCM tool. It just
> comes down to the fact that I am better with Ruby.
Yes ... I understand the need to create and need to innovate as much as
anyone. However, there are lots of worthwhile projects that are begging
for developers to enhance and maintain them while other developers are
re-inventing wheels, levers, inclined planes and pulleys. And there's
even more "worthwhile" open source software that is languishing because
only other programmers can use it!

Yeah. I can agree here. So I am asking if anyone else has a nice
project where I might be able to lend my skills. I really think it is
a an important thing to discuss on a mailing list like this because
more people become aware of others who share their interest in
projects.

Now in the specific case of version control systems, the main reason
there seem to be so many of them is that different project management
schemes have different requirements, and only the heavy-duty industrial
strength (and expensive) ones like ClearCase have any hope of covering
lots of those bases. And before you go beating up on ClearCase, I don't
happen to be a big fan of it, I know it has warts, but it's what's
mandated in a lot of places.

CVS is still "good enough" for lots of SCM users, and between CVS and
SVN, there's not much need for more innovation as far as I'm concerned.
One of the big principles of "agile" and "pragmatic" development is
YAGNI -- You Ain't Gonna Need It!

Right but also a little wrong. There are plenty of cases where I still
reluctantly use svn (job being one -- though they are becoming more
open to alternatives). I think it is perfectly fine to put getting
real work done high on the priority scale. It doesn't mean we
shouldn't ever ignore things that never translate to getting things
done.

Over time everyone develops a bit of an environment that seems to work
but sometime there are small gaps in the workflow. Taking the leap to
fill that can sometimes mean an interruption in real work. Trying all
day to fill these is bound to get you about as far as perl 6 }}:-).
Trying to improve things here and there might just lead to a little
more enjoyment if you spend as much time in such an environment as I
do.

Balance in everything might we a way to look at it.

>
> sarcasm do
>
> For that, why are we even speaking multiple of anything? Why don't we
> all use the same language, the same OS, the same hardware... and while
> we are at it, we can have the same attitude ideas and personalities.
>
> end
Well, actually, we pretty much do all use the same language -- C and
dialects of C -- and we pretty much all do use the same hardware -- x86
and x86-64. We pretty much all have a "File" menu in the upper left
corner, we pretty much all have a mouse and a keyboard and a color
graphical display, we pretty much all talk to each other using IPV4 and
dozens of other standard protocols, etc., etc. Innovations need to be
*compelling* to get someone to use something else.

I don't really think of Ruby as innovative -- one of the charming things
about Ruby is that it is a collection of good ideas that have stood the
test of time. Regular expressions, classes, objects and methods, dynamic
"typing", flexible syntax, "it's always run time", continuations,
arbitrary precision integer arithmetic, flexible arrays and hashes ---
these are all wheels that Ruby didn't re-invent!

Right. Sorry, I should have dropped my sarcastic comment. I just get
tired of people complaining about something that they don't find an
interest in when it is a public forum. It did let me blow a little
steam though ;-). On the other hand, it might show how far some people
take the assumption of Yet Another *.

Thinking out loud again:

People asking why we are building yet-another-ruby implementation
should probably sit in on the discussions that go in the community
before they blast out asking everyone to go work on a single project.
I bet each project has its own interesting points that they are trying
to address.

So is fragmentation the worst of the open source community's problems?
Not really. It comes down to communication. Advertising the existence
and making ideas addressable is really a break past the fog. We can
already see some mixing because of this in projects like JRuby and
Rubinius.

Brian.

···

On 1/16/07, M. Edward (Ed) Borasky <znmeb@cesmail.net> wrote:

Hey Ed,

> VS is still "good enough" for lots of SCM users, and between CVS and SVN, there's not much need for more innovation as far as I'm concerned. One of the big principles of "agile" and "pragmatic" development is YAGNI -- You Ain't Gonna Need It!

I think there's heaps of room for new ideas and innovation in the SCM area. There are a fair number of tools floating around with various unique features and approaches. If the area was dead I think we'd just see one or two tools gain and hold dominance.

> I don't really think of Ruby as innovative -- one of the charming things about Ruby is that it is a collection of good ideas that have stood the test of time. Regular expressions, classes, objects and methods, dynamic "typing", flexible syntax, "it's always run time", continuations, arbitrary precision integer arithmetic, flexible arrays and hashes --- these are all wheels that Ruby didn't re-invent!

The appeal of Ruby to me is its incredible flexibility and the ability to develop small bodies of code in it *really* fast. There's no fighting the compiler or dealing with odd legacy requirements. You aren't pressured into a particular paradigm, and you can be sloppy if you want. It bundles a whole bunch of good ideas together and makes it available for you in a single language. The focus seems to be on flexibility and powerful expression, which leads to elegant solutions not always possible in other languages. You can experiment and prototype incredibly quickly. It also scales well provided that you don't go too far into the tens of thousands of lines of code.

I'd still go for a C++-like language for larger projects, because when I'm working on them I want the compiler to be absolutely pedantic and complain about every single thing it can, and I want complete control over how it works. But for many other things, Ruby is outstanding.

Garth

- Does the test code look okay? Did I make any mistakes? I'm only human, and
   the crash test isn't trivial.

Nothing caught my eye at first glance, but I have not yet looked at it
deeply.

- Does "./foo 3" also crash on your machine? Or is it just mine?

I cannot get it to crash on my box (64-bits, thou)... 750+ and counting

- I use alloca to simulate calls to functions with different stack depth
   requirements. If you object to alloca, please note that mode 2 of the
   test program works perfectly fine- this is heavy alloca use without Ruby
   calls. It crashes only when we add Ruby calls to the mix.

Use of alloca can be problematic if you are using latest SVN ruby
(according to a recent ChangeLog). Ruby provides some ALLOCA macros
for the same behavior, called ALLOCA_N() and in the new ruby's
C_ALLOCA, I believe. Also, these macros will invoke the gc in case of
lack of memory, which is also a good idea, anyway.

- As noted, I think it only happens if profiling is enabled. I can't guarantee
   it doesn't crash without, I just haven't seen it do so.

A simpler possibility for this is that ruby might be running out of
stack space in your process.
The current ruby interpreter is notoriously bad for the way it
allocates its stack frames. If you end doing a lot of deep nested
calls, you can hit the limits.
As you are on linux, you can test this rather easily.

Try increasing the value of ulimit, from its default.

ulimit -s
ulimit -s XXXX # like double your previous limit

See if the crash happens at the same place, or if it occurs somewhat
later (or not at all).
If that's what happens, I'm afraid you'll need to modify the process
stack depth for your application, or always run your code thru a bash
wrapper script that sets ulimit.

Hey gga,

gga wrote:
>>- Does "./foo 3" also crash on your machine? Or is it just mine?
>
> I cannot get it to crash on my box (64-bits, thou)... 750+ and counting

Interesting. Mine is pretty-much guaranteed to die between 100 and 200
iterations. Generally if it makes it that far, it's going to make it the
whole way.

For sake of comparison, what do you get on that same box for:

ruby -v
g++ -v
uname -a

>>- I use alloca to simulate calls to functions with different stack depth
>> requirements. If you object to alloca, please note that mode 2 of the
>> test program works perfectly fine- this is heavy alloca use without Ruby
>> calls. It crashes only when we add Ruby calls to the mix.
>
> Use of alloca can be problematic if you are using latest SVN ruby
> (according to a recent ChangeLog). Ruby provides some ALLOCA macros
> for the same behavior, called ALLOCA_N() and in the new ruby's
> C_ALLOCA, I believe. Also, these macros will invoke the gc in case of
> lack of memory, which is also a good idea, anyway.

I hope the use of an alternate alloca is merely an internal thing and
doesn't impose an external requirement on code using embedded Ruby.
Requiring that the host program not use alloca would be pretty harsh.
I generally don't use it (though I did for my example code), but I can't
guarantee the other libraries I am also using don't use it. As such, that
might be the limitation in common. I hope not...

>>- As noted, I think it only happens if profiling is enabled. I can't guarantee
>> it doesn't crash without, I just haven't seen it do so.
>
> A simpler possibility for this is that ruby might be running out of
> stack space in your process.
> The current ruby interpreter is notoriously bad for the way it
> allocates its stack frames. If you end doing a lot of deep nested
> calls, you can hit the limits.
> As you are on linux, you can test this rather easily.
>
> Try increasing the value of ulimit, from its default.
>
>>ulimit -s
>>ulimit -s XXXX # like double your previous limit

This was a really good idea, I was crossing my fingers and hoping it
would work.

Alas, it still fails at around the same spot with the limit set to
10240, 81920, 163840, and 655360. No major behavioral change. :frowning:
Original was 10240.

Since I normally launch via tcsh, I issued a "limit" and got 10240
(same as bash). To be sure, I issued a "limit stacksize unlimited", and
gave it one last run. It doesn't help, still dies at 125. :frowning:

It sounded feasible though. Stack-based errors, profiler information may
flood stack usage, and put in a large program- it could quite easily have
been the cause.

Thanks for giving things a whirl.

Current plan: Trying out a few different versions of Ruby to see the effect.
Hopefully I have some more information tomorrow.

Garth

Hey all,

Okay, I have some more information.

Re the use of alloca in foo.cpp, I remembered a GNU extension that I rarely
use, and it can be safely swapped in. In foo.cpp, replace:

   unsigned char *data = (unsigned char *)alloca(ss);

with:

   unsigned char data[ss];

I generally prefer to keep my code portable, but this serves to shift the
potential blame away from alloca somewhat. The sample code still crashes,
just not in the same point. alloca is not to blame.

I've rebuilt the same foo.cpp code with multiple versions of Ruby and
tabulated the results:

(best viewed in fixed-width)

Version Mode 3 Mode 1
------- ------ ------
1.8.5-p12 125
1.8.4 91
1.6.8 0 0
Stable repos snapshot 125
Nightly checkout snapshot 0 0

Snapshots were downloaded on 22/1/2007, SA Central time (SA).

In each case any minor modifications required to make it build (eg. fixing
prototypes) were made.

In all cases the sample code (foo.cpp) crashed.

Mode 3 refers to the iteration that it crashed when run with "messy".
Mode 1 refers to crashes when run on its own, ie. without "messy".
A result of 0 means it crashed before it started iterating. Blank means it
was not run- I only bothered in the cases where Mode 3 crashed quickly.

The gist is that the sample code provided will crash on every version I
tried (1.6.8, 1.8.4, 1.8.5-p12, latest stable and unstable CVS). It is fair
to assume it will fail on many more.

Approaching the problem from another angle, I figured I'd try different
tricks when building Ruby itself. For the following tests I used 1.8.5-p12
as a base.

Modification Mode 3 Mode 1
------------ ------ ------
Base (for comparison) 125
Link with static version instead ~90 [1]
CPPFLAGS="-g -pg" 19
Strip out -O2 0 153 (!?!?)
Replace -O2 with -O 18

[1] - Forgot to record actual number, but it was around 90 or so.

And last of all, I just wanted to confirm that when running in the default
configuration without "-pg", the sample code made 10000 iterations without
a crash. Took most of the day to run too. :wink:

Other pertinent information from my previous post:

> uname -a
Linux notimportant 2.6.18-1.2798.fc6 #1 SMP Mon Oct 16 14:54:20 EDT 2006 i686 athlon i386 GNU/Linux

> g++ -v
Using built-in specs.
Target: i386-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-libgcj-multifile --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre --with-cpu=generic --host=i386-redhat-linux
Thread model: posix
gcc version 4.1.1 20061011 (Red Hat 4.1.1-30)

Maybe it is a gcc 4.* thing? Anyone else running a similar system (ie. FC6)
able to give things a shot?

So there we go. I'm not sure what else I can provide at this point. I've
provided sample code that triggers the crash, tried it on multiple versions
of Ruby, isolated it down to the -pg switch, so forth. I believe I've fielded
any concerns on the sample code adequately. This is a fairly significant bug
for anyone embedding Ruby in a project that needs profiling information-
assuming it affects other people as well- as it seems to affect multiple
versions of Ruby and makes the program unreliable and crash-prone.

My offer to assist remains open; I can be reached via email from the contact
page on www.entropicsoftware.com. I do hope that the days of work I've put
into diagnosing this problem somehow pays off in locating the source of this
significant bug.

Now I feel it is time to take a break from Embedded Ruby and play around with
some alternate solutions. Working on this has certainly been an interesting
experience.

Please don't hesitate to ask if I can provide any additional information or
data from additional tests.

Take care,
Garth