Hi all,
I'm having some issues with some custom embedding of the PHP sapi. I'm
trying to call PHP from Ruby and I'd like to be able to pass data back
and forth freely, but I'm running into segfaults. It works well enough
for small values, but for some large values, it crashes on me.
Currently my most immediate issue is when I'm passing a large string
to call_user_function, which itself is calling token_get_all. The file
I'm parsing is pretty big, so the hash table returned is also pretty
big (~500 records). But each time I loop through it, it segfaults half
way through, even if I don't touch the records at all. I ran gdb on it
and it tells me one of the internal hash pointers is invalid, which
I'm not sure how this could have happened, since I'm only iterating
through it. I've included a version of the function doing this below
[2], and a sample of the gdb session I used as well [3]. If you'd like
to see the original, plus the context of this operation, you can check
it out here [1].
I have a hunch the problem lies in the way I'm allocating (or not
allocating) the PHP variables involved. I did follow some of the
guidelines in the book "Extending and Embedding PHP", but found that
my code worked without all of the conventions, so instead I just
omitted it when it didn't seem necessary.. And now I'm here :) If it
is down to my bad memory handling habits, it would really be helpful
if someone could point out, on what particular line, I'm doing things
wrong. Then I could probably figure it out from there.
Thanks,
- Farley
[2] Code sample:
VALUE zval2rb_hsh_(zval zhash) {
VALUE rbhash = rb_hash_new();
char *string_key;
ulong num_key;
zval key, **value;
VALUE rbkey, rbvalue;
zend_hash_internal_pointer_reset(Z_ARRVAL(zhash));
printf("This hash table has %d entries\n",
zend_hash_num_elements(Z_ARRVAL(zhash)));
int current = 0;
while (zend_hash_get_current_data(Z_ARRVAL(zhash), (void**)&value)
== SUCCESS) {
current++;
printf("Currently on entry %d\n", current);
if (zend_hash_move_forward(Z_ARRVAL(zhash)) == SUCCESS)
printf("Done moving hash forward. Result was successful\n");
else
printf("Done moving hash forward. Result was a failure\n");
}
return rbhash;
}
[3] gdb session:
gdb ruby
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...
(gdb) run test.rb
Starting program: /usr/local/bin/ruby test.rb
[Thread debugging using libthread_db enabled]
Error while reading shared library symbols:
Cannot find new threads: generic error
Cannot find new threads: generic error
(gdb) continue
Continuing.
calling phpversion
5.2.9
calling token get all, medium input
This hash table has 429 entries
Currently on entry 1
Done moving hash forward. Result was successful
Currently on entry 2
....
....
Done moving hash forward. Result was successful
Currently on entry 291
Done moving hash forward. Result was successful
[New Thread 0xb7d846b0 (LWP 13069)]
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb7d846b0 (LWP 13069)]
zend_hash_get_current_data_ex (ht=0x817fc48, pData=0xbfa3acb8,
pos=0x0) at /home/robinhoode/Desktop/php-5.2.9/Zend/zend_hash.c:1163
1163 *pData = p->pData;
(gdb) quit
The program is running. Exit anyway? (y or n) y
zend_hash_internal_pointer_reset(Z_ARRVAL(zhash));
printf("This hash table has %d entries\n",
zend_hash_num_elements(Z_ARRVAL(zhash)));int current = 0;
while (zend_hash_get_current_data(Z_ARRVAL(zhash), (void**)&value)
== SUCCESS) {
current++;
printf("Currently on entry %d\n", current);
if (zend_hash_move_forward(Z_ARRVAL(zhash)) == SUCCESS)
printf("Done moving hash forward. Result was successful\n");
else
printf("Done moving hash forward. Result was a failure\n");
}
Does the problem persist if replacing the hashtable functions by the
_ex counterparts: zend_internal_pointer_reset_ex(),
zend_hash_get_current_data_ex() and zend_move_forward_ex()? These are
always recommended (I believe) because the internal HashPosition value
associated to a hashtable is also used in the user script.
Regards,
Moriyoshi
zend_hash_internal_pointer_reset(Z_ARRVAL(zhash));
printf("This hash table has %d entries\n",
zend_hash_num_elements(Z_ARRVAL(zhash)));int current = 0;
while (zend_hash_get_current_data(Z_ARRVAL(zhash), (void**)&value)
== SUCCESS) {
current++;
printf("Currently on entry %d\n", current);
if (zend_hash_move_forward(Z_ARRVAL(zhash)) == SUCCESS)
printf("Done moving hash forward. Result was successful\n");
else
printf("Done moving hash forward. Result was a failure\n");
}Does the problem persist if replacing the hashtable functions by the
_ex counterparts: zend_internal_pointer_reset_ex(),
zend_hash_get_current_data_ex() and zend_move_forward_ex()? These are
always recommended (I believe) because the internal HashPosition value
associated to a hashtable is also used in the user script.Regards,
Moriyoshi
Actually I believe I did, but if they are recommended, I suppose I
will use them instead. Thanks for pointing that out.
BTW I did provide a link to the rest of the code, but I realize what I
posted above might not be enough to understand where the bug lies.
Should I bother posting a larger portion?
Thanks,
- Farley
while (zend_hash_get_current_data(Z_ARRVAL(zhash), (void**)&value)
== SUCCESS) {
current++;
printf("Currently on entry %d\n", current);
if (zend_hash_move_forward(Z_ARRVAL(zhash)) == SUCCESS)
printf("Done moving hash forward. Result was successful\n");
else
printf("Done moving hash forward. Result was a failure\n");
}
What's the point of this if() ?
You continue reading the values even if move_forward() fails (i.e. the end is reached).
--
Wbr,
Antony Dovgal
while (zend_hash_get_current_data(Z_ARRVAL(zhash), (void**)&value)
== SUCCESS) {
current++;
printf("Currently on entry %d\n", current);
if (zend_hash_move_forward(Z_ARRVAL(zhash)) == SUCCESS)
printf("Done moving hash forward. Result was successful\n");
else
printf("Done moving hash forward. Result was a failure\n");
}What's the point of this if() ?
You continue reading the values even if move_forward() fails (i.e. the end is reached).
I threw that in for debugging purposes.. So it's completely useless otherwise :)
--
Wbr,
Antony Dovgal
- Farley