After taking a look at the source, I can see where the problem is. As
you suspected, the behavior you are seeing is related to the change
you made. In this particular case, rb_str_new2() cannot be used.
The difference between rb_str_new() and rb_str_new2() is that when
using rb_str_new() you explicitly pass in the length of the buffer,
whereas rb_str_new2 uses the strlen() function to determine the length
and then calls rb_str_new(). (You can look at the code for these
functions at
http://ruby-doc.org/doxygen/1.8.4/string_8c-source.html#l00101)
The problem is that strlen() can only determine the length of the
string if the string is null-terminated. If you look in the
sqlanywhere.c code (
http://github.com/sqlanywhere/sqlanywhere/blob/
master/ext/sqlanywhere.c#L153), you will see that the results from the
database come back as a a_sqlany_data_value structure that contains
three fields:
type - What data type is represented in the buffer
buffer - The raw bits of the data
length - The length of the buffer
Based on the type field, the buffer is cast into the correct Ruby
type. The problem is that the buffer is not null terminated since the
length is explicitly passed, and null-termination makes no sense for
the other data types.
What is happening when you use rb_str_new2() is that the strlen()
function is returning a distance to the next null-terminator which is
"beyond" the end of the string in memory. When this length is memory-
copied, it will contain apparently random data (whatever happened to
be in memory next to the string) at the end.
So in this case we need to us rb_str_new(). Of course, that still
leaves the problem of why you are seeing "failed to
allocate memory". Can you describe when exactly you saw that message?
Thanks,
- Eric