New extension; nested function calls failing

php.internals

Bob Glamm

23 years ago
(Apologies if this is the wrong list or if the answer to this has escaped my searches, but I'm at my wit's end at the moment). I'm trying to get a libical binding going for PHP (v4.3.2, with plans to port to 5.0 as soon as it works with v4.3.x). At the moment, this PHP code works: $x = icalcomponent_new_vcalendar(); $y = icalcomponent_new_vevent(); $x->add_component($y); but this fails: $x = icalcomponent_new_vcalendar(); $x->add_component(icalcomponent_new_vevent()); Both icalcomponent_new_vcalendar() and icalcomponent_new_vevent() return icalcomponent classes from the extension. Icalcomponent has one data member ("resource") holding an icalcomponent *, and a class entry containing a list of functions (such as "add_component") that can be used to manipulate the component. I've attempted to debug this - in the failing case the vcalendar component and the vevent component are created correctly, but when icalcomponent_new_vevent() returns something happens so that add_component isn't being found properly: $ gdb ../../../sapi/cli/php core GNU gdb 5.3 Core was generated by `../../../sapi/cli/php t1.php'. Program terminated with signal 11, Segmentation fault. #0 call_overloaded_function (T=0xa0dc624c, arg_count=1, return_value=0x81d86b4) at /tmp/new_installation/php-4.3.2-devel/Zend/zend_execute.c:966 966 ce = Z_OBJCE_P(T->EA.data.overloaded_element.object); (gdb) where #0 call_overloaded_function (T=0xa0dc624c, arg_count=1, return_value=0x81d86b4) at /tmp/new_installation/php-4.3.2-devel/Zend/zend_execute.c:966 #1 0x081492ea in execute (op_array=0x81d416c) at /tmp/new_installation/php-4.3.2-devel/Zend/zend_execute.c:1672 #2 0x0813cbf8 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at /tmp/new_installation/php-4.3.2-devel/Zend/zend.c:869 #3 0x08117630 in php_execute_script (primary_file=0xbffff460) at /tmp/new_installation/php-4.3.2-devel/main/main.c:1671 #4 0x0814d986 in main (argc=2, argv=0xbffff4f4) at /tmp/new_installation/php-4.3.2-devel/sapi/cli/php_cli.c:806 #5 0x4010af64 in __libc_start_main (main=0x814d1d0 <main>, argc=2, ubp_av=0x0, init=0x8066d68 <_init>, fini=0x1, rtld_fini=0x81d84a0, stack_end=0x807e0b0) at ../sysdeps/generic/libc-start.c:144 (In the call_overloaded_function frame, the T parameter pointer is invalid). This is the relevant code that is being called in the extension; perhaps somewhere I am not constructing/returning an icalcomponent class zval properly? static void icalcomponent_new_return(zval *rv, icalcomponent *icc) { zend_class_entry *ce, icalcomponent_entry; zval *res; int resid; INIT_CLASS_ENTRY(icalcomponent_entry, "icalcomponent", icalcomponenttype_functions); ce = zend_register_internal_class(&icalcomponent_entry TSRMLS_CC); object_init_ex(rv, ce); MAKE_STD_ZVAL(res); resid = ZEND_REGISTER_RESOURCE(res, icc, icalcomponent_resource_id); add_property_resource(rv, "resource", resid); } static ZEND_FUNCTION(icalcomponent_new_vcalendar) { if(ZEND_NUM_ARGS() != 0) WRONG_PARAM_COUNT; icalcomponent_new_return(return_value, icalcomponent_new_vcalendar()); } static ZEND_FUNCTION(icalcomponent_new_vevent) { if(ZEND_NUM_ARGS() != 0) WRONG_PARAM_COUNT; icalcomponent_new_return(return_value, icalcomponent_new_vevent()); } static ZEND_NAMED_FUNCTION(zif_icalcomponent_add_component) { zval **entry, *icc_obj; zend_class_entry icalcomponenttype_entry; icalcomponent *icc = NULL, *child = NULL; if(ZEND_NUM_ARGS() != 1) WRONG_PARAM_COUNT; INIT_CLASS_ENTRY(icalcomponenttype_entry, "icalcomponent", icalcomponenttype_functions); if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &icc_obj) == FAILURE) return; if(zend_hash_find(HASH_OF(getThis()), "resource", sizeof("resource"), (void **)&entry) == SUCCESS && Z_TYPE_PP(entry) == IS_RESOURCE) ZEND_FETCH_RESOURCE(icc, icalcomponent *, entry, -1, ICALCOMPONENT_RESOURCE, icalcomponent_resource_id); if(!icc || !icalcomponent_isa_component(icc) || !icalcomponent_is_valid(icc)) return; if(zend_hash_find(HASH_OF(icc_obj), "resource", sizeof("resource"), (void **)&entry) == SUCCESS && Z_TYPE_PP(entry) == IS_RESOURCE) ZEND_FETCH_RESOURCE(child, icalcomponent *, entry, -1, ICALCOMPONENT_RESOURCE, icalcomponent_resource_id); if(!child || !icalcomponent_isa_component(child) || !icalcomponent_is_valid(child)) return; icalcomponent_add_component(icc, child); } Any help would be appreciated. Thanks in advance. -Bob

Bob Glamm

23 years ago
Please disregard this, I found the problem - namely, zend_register_internal_class should be called once on module initialization per internal class, not once per class instantiation. -Bob