I'm wondering if anyone can help me. I have been working on a php extension for google-sparsehashmap which I have working as I would / need it to, all except iteration.
I have been scratching my head for weeks trying to get it to work, using the classes built in iterator.
According to the backtrace I done on my test file, this is where SIGSEGV is thrown
static zval* php_sparsehashmap_iterator_current_data(php_sparsehashmap_iterator_t *iterator) {
php_sparsehashmap_iterator_t *io = (php_sparsehashmap_iterator_t*)iterator;
zend_string *_data;
zval *data;
_php_sparsehashmap_t *sp = PHP_SPARSEHASHMAP_FETCH_FROM(Z_OBJ(io->sparsehashmap));
std::string current_data = sp->shm->current_data();
_data = zend_string_init(current_data.c_str(), strlen(current_data.c_str()), 0);
ZVAL_STR(data, _data);
return data;
}
This is what GDB gives me when I run my test file.
Program received signal SIGSEGV, Segmentation fault.
php_sparsehashmap_iterator_current_data (iterator=<optimized out>) at php-sparsehashmap/iterator.cc:58
58 ZVAL_STR(data, _data);
(gdb) bt
#0 php_sparsehashmap_iterator_current_data (iterator=<optimized out>) at php-sparsehashmap/iterator.cc:58
#1 0x000055555586d215 in ?? ()
#2 0x0000555555875daf in execute_ex ()
#3 0x000055555587da21 in zend_execute ()
#4 0x00005555557f6963 in zend_execute_scripts ()
#5 0x0000555555795cc0 in php_execute_script ()
#6 0x000055555587fb56 in ?? ()
#7 0x000055555565bebb in ?? ()
#8 0x00007ffff764109b in __libc_start_main (main=0x55555565ba70, argc=2, argv=0x7fffffffe5d8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe5c8)
at ../csu/libc-start.c:308
#9 0x000055555565c01a in _start ()
For a better look at what is happening when the Segmentation Fault occurs, I have run with valgrind
with the options --leak-check=full
and --track-origin=yes
set.
==15401== Invalid write of size 8
==15401== at 0xA1743D3: php_sparsehashmap_iterator_current_data(_php_sparsehashmap_iterator_t*) (iterator.cc:67)
==15401== by 0x421214: ??? (in /usr/bin/php7.4)
==15401== by 0x429DAE: execute_ex (in /usr/bin/php7.4)
==15401== by 0x431A20: zend_execute (in /usr/bin/php7.4)
==15401== by 0x3AA962: zend_execute_scripts (in /usr/bin/php7.4)
==15401== by 0x349CBF: php_execute_script (in /usr/bin/php7.4)
==15401== by 0x433B55: ??? (in /usr/bin/php7.4)
==15401== by 0x20FEBA: ??? (in /usr/bin/php7.4)
==15401== by 0x505B09A: (below main) (libc-start.c:308)
==15401== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==15401==
==15401==
==15401== Process terminating with default action of signal 11 (SIGSEGV)
==15401== Access not within mapped region at address 0x0
==15401== at 0xA1743D3: php_sparsehashmap_iterator_current_data(_php_sparsehashmap_iterator_t*) (iterator.cc:67)
==15401== by 0x421214: ??? (in /usr/bin/php7.4)
==15401== by 0x429DAE: execute_ex (in /usr/bin/php7.4)
==15401== by 0x431A20: zend_execute (in /usr/bin/php7.4)
==15401== by 0x3AA962: zend_execute_scripts (in /usr/bin/php7.4)
==15401== by 0x349CBF: php_execute_script (in /usr/bin/php7.4)
==15401== by 0x433B55: ??? (in /usr/bin/php7.4)
==15401== by 0x20FEBA: ??? (in /usr/bin/php7.4)
==15401== by 0x505B09A: (below main) (libc-start.c:308)
==15401== If you believe this happened as a result of a stack
==15401== overflow in your program's main thread (unlikely but
==15401== possible), you can try to increase the size of the
==15401== main thread stack using the --main-stacksize= flag.
==15401== The main thread stack size used in this run was 8388608.
==15401==
==15401== HEAP SUMMARY:
==15401== in use at exit: 3,367,736 bytes in 26,417 blocks
==15401== total heap usage: 128,270 allocs, 101,853 frees, 22,900,347 bytes allocated
==15401==
==15401== LEAK SUMMARY:
==15401== definitely lost: 96 bytes in 4 blocks
==15401== indirectly lost: 0 bytes in 0 blocks
==15401== possibly lost: 2,338,288 bytes in 18,657 blocks
==15401== still reachable: 1,029,352 bytes in 7,756 blocks
==15401== suppressed: 0 bytes in 0 blocks
To make things a little easier, I've uploaded to a git repo for full visibility on the code, as well as the required class which can be found in this Github Repo.
I know it doesn't look 100% amazing, this is my first attempt at C/C++/php extensions, so I have been learning a lot while building this.
Thanks in advance, any help getting this working finally would be greatly appreciated.
The problem is that data
points to uninitialized memory. You need to
actually have a zval
somewhere, which is usually in the
php_<extension_name>_iterator_t
structure.
static zval* php_<extension_iterator_name>_current_data
requires a zval*
return, but you cannot return an internal function variable, as it will not be initialised outside the scope of the function.
Instead, create a zval
variable within your iterator structure, return the value of the iterator zval
in the <extension_iterator_name>_current_data()
function. i.e.
/* {{{ */
typedef struct _php_sparsehashmap_iterator_t {
zend_object_iterator it;
zval zdata;
zend_long pos;
} php_sparsehashmap_iterator_t; /* }}} */
/* {{{ */
zend_object_iterator* php_sparsehashmap_iterator(zend_class_entry *ce, zval *sparsehashmap, int by_ref) {
zend_string *_data;
php_sparsehashmap_iterator_t *io = (php_sparsehashmap_iterator_t*) emalloc(sizeof(php_sparsehashmap_iterator_t));
zend_iterator_init((zend_object_iterator*) io);
io->pos = 0;
io->it.funcs = &php_sparsehashmap_iterator_funcs;
std::string current_data = get_current_data();
_data = zend_string_init(current_data.c_str(), strlen(current_data.c_str()), 0);
ZVAL_STR(&io->zdata, _data);
return (zend_object_iterator*) io;
} /* }}} */
static zval* php_sparsehashmap_iterator_current_data(php_sparsehashmap_iterator_t *iterator) {
php_sparsehashmap_iterator_t *io = (php_sparsehashmap_iterator_t*)iterator;
return &io->zdata;
}