Edit report at http://bugs.php.net/bug.php?id=51768&edit=1
ID: 51768 Updated by: cataphr...@php.net Reported by: cataphr...@php.net Summary: Fallback to read_property causes subsequent crash Status: Open Type: Bug Package: Reproducible crash Operating System: Windows PHP Version: 5.3.2 New Comment: Apparently, not to break backwards compatibility, $a = &$obj->prop should not accept only references, like read_dimension. The current behavior is to make a reference if the refcount is one (SEPARATE_ZVAL_TO_MAKE_IS_REF). Anyway, in the test script the refcount is 2. Previous Comments: ------------------------------------------------------------------------ [2010-05-08 16:01:21] cataphr...@php.net I got it backwards in the expected behavior and a bit in the description. What should give a fatal error is something like: $obj->prop = &$a; I said that $a = &$obj['prop'] emits an error. It doesn't. It emits a notice if the zval* returned by the read_dimension handler does not return a reference (Indirect modification of overloaded element). In fact both read_dimension and read_property without get_property_ptr_ptr behave correctly in the $obj->prop = &$a by emitting a fatal error: (Cannot assign by reference to overloaded object) The expected behavior should then be either mimic read_dimension (accept only references) or just throw an error. ------------------------------------------------------------------------ [2010-05-08 04:14:05] cataphr...@php.net Description: ------------ When the get_property_ptr_ptr handler is omitted, zend_fetch_property_address falls back to read_property, but then the behavior in cases such as $a = &$obj->prop; deviates from that of $a = &$obj['prop']; which properly emits an error. The final result is a crash. Test script: --------------- exttest.h: #ifndef PHP_EXTTEST_H # define PHP_EXTTEST_H # ifdef HAVE_CONFIG_H # include<config.h> # endif # include<php.h> extern zend_module_entry exttest_module_entry; #define phpext_exttest_ptr &exttest_module_entry #endif exttest.c: #include "exttest.h" static zend_object_handlers object_handlers; static zend_object_value ce_create_object(zend_class_entry *class_type TSRMLS_DC) { zend_object_value zov; zend_object *zobj; zobj = emalloc(sizeof *zobj); zend_object_std_init(zobj, class_type TSRMLS_CC); zend_hash_copy(zobj->properties, &(class_type->default_properties), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval*)); zov.handle = zend_objects_store_put(zobj, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) zend_objects_free_object_storage, NULL TSRMLS_CC); zov.handlers = &object_handlers; return zov; } ZEND_MODULE_STARTUP_D(exttest) { zend_class_entry ce; zend_class_entry *ce_ptr; zval *property; ALLOC_PERMANENT_ZVAL(property); INIT_ZVAL(*property); Z_TYPE_P(property) = IS_LONG; Z_LVAL_P(property) = 20l; memcpy(&object_handlers, zend_get_std_object_handlers(), sizeof object_handlers); object_handlers.get_property_ptr_ptr = NULL; INIT_CLASS_ENTRY(ce, "TestClass", NULL); ce_ptr = zend_register_internal_class(&ce TSRMLS_CC); ce_ptr->create_object = ce_create_object; zend_declare_property_ex(ce_ptr, "prop", 4, property, ZEND_ACC_PUBLIC, NULL, 0 TSRMLS_CC); } zend_module_entry exttest_module_entry = { STANDARD_MODULE_HEADER, "exttest", NULL, /* Functions */ ZEND_MODULE_STARTUP_N(exttest) , /* MINIT */ NULL, /* MSHUTDOWN */ NULL, /* RINIT */ NULL, /* RSHUTDOWN */ NULL, /* MINFO */ NO_VERSION_YET, STANDARD_MODULE_PROPERTIES }; ZEND_GET_MODULE(exttest) config.m4: PHP_ARG_ENABLE(exttest, [Whether to enable the "exttest" extension], [ enable-exttest Enable "exttest" extension support]) if test $PHP_EXTTEST != "no"; then PHP_SUBST(EXTTEST_SHARED_LIBADD) PHP_NEW_EXTENSION(exttest, exttest.c, $ext_shared) fi test.php: <?php $obj = new TestClass(); debug_zval_dump($obj); $a = &$obj->prop; debug_zval_dump($obj); debug_zval_dump(&$a); $a = 40; debug_zval_dump($obj); debug_zval_dump(&$a); unset($a); debug_zval_dump($obj); Expected result: ---------------- Expected an error saying the operation is not permitted (like when attempting $a = &obj['index'] where there's no get_property_ptr_ptr equivalent). Actual result: -------------- When thre's get_property_ptr_ptr: object(TestClass)#1 (1) refcount(2){ ["prop"]=> long(20) refcount(2) } object(TestClass)#1 (1) refcount(2){ ["prop"]=> &long(20) refcount(2) } &long(20) refcount(3) object(TestClass)#1 (1) refcount(2){ ["prop"]=> &long(40) refcount(2) } &long(40) refcount(3) object(TestClass)#1 (1) refcount(2){ ["prop"]=> long(40) refcount(1) } When there's no get_property_ptr_ptr, zend_fetch_property_address falls back to read_propert. Something happens afterwards that provokes the crash. object(TestClass)#1 (1) refcount(2){ ["prop"]=> long(20) refcount(2) } object(TestClass)#1 (1) refcount(2){ ["prop"]=> long(20) refcount(1) } &long(20) refcount(3) object(TestClass)#1 (1) refcount(2){ ["prop"]=> long(20) refcount(1) } &long(40) refcount(3) object(TestClass)#1 (1) refcount(2){ ["prop"]=> long(20) refcount(1) } Segmentation fault #0 0x081d60ae in zend_mm_check_ptr (heap=0x83881b8, ptr=0x840ca90, silent=1, __zend_filename=0x83633a0 "/home/glopes/php/php-5.3.2/Zend/zend_variables.c", __zend_lineno=178, __zend_orig_filename=0x83621b8 "/home/glopes/php/php-5.3.2/Zend/zend_execute_API.c", __zend_orig_lineno=440) at /home/glopes/php/php-5.3.2/Zend/zend_alloc.c:1347 #1 0x081d768d in _zend_mm_free_int (heap=0x83881b8, p=0x840ca90, __zend_filename=0x83633a0 "/home/glopes/php/php-5.3.2/Zend/zend_variables.c", __zend_lineno=178, __zend_orig_filename=0x83621b8 "/home/glopes/php/php-5.3.2/Zend/zend_execute_API.c", __zend_orig_lineno=440) at /home/glopes/php/php-5.3.2/Zend/zend_alloc.c:1983 #2 0x081d86bb in _efree (ptr=0x840ca90, __zend_filename=0x83633a0 "/home/glopes/php/php-5.3.2/Zend/zend_variables.c", __zend_lineno=178, __zend_orig_filename=0x83621b8 "/home/glopes/php/php-5.3.2/Zend/zend_execute_API.c", __zend_orig_lineno=440) at /home/glopes/php/php-5.3.2/Zend/zend_alloc.c:2351 #3 0x081e9944 in _zval_ptr_dtor (zval_ptr=0x841d584, __zend_filename=0x83633a0 "/home/glopes/php/php-5.3.2/Zend/zend_variables.c", __zend_lineno=178) at /home/glopes/php/php-5.3.2/Zend/zend_execute_API.c:440 #4 0x081f7ca8 in _zval_ptr_dtor_wrapper (zval_ptr=0x841d584) at /home/glopes/php/php-5.3.2/Zend/zend_variables.c:178 #5 0x08207cf7 in zend_hash_destroy (ht=0x841d520) at /home/glopes/php/php-5.3.2/Zend/zend_hash.c:526 #6 0x0821d64d in zend_object_std_dtor (object=0x841ccf8) at /home/glopes/php/php-5.3.2/Zend/zend_objects.c:45 #7 0x0821d9a9 in zend_objects_free_object_storage (object=0x841ccf8) at /home/glopes/php/php-5.3.2/Zend/zend_objects.c:114 #8 0x0822252b in zend_objects_store_del_ref_by_handle_ex (handle=1, handlers=0xb7f1bd60) at /home/glopes/php/php-5.3.2/Zend/zend_objects_API.c:220 #9 0x08222320 in zend_objects_store_del_ref (zobject=0x841c45c) at /home/glopes/php/php-5.3.2/Zend/zend_objects_API.c:172 #10 0x081f7917 in _zval_dtor_func (zvalue=0x841c45c, __zend_filename=0x83621b8 "/home/glopes/php/php-5.3.2/Zend/zend_execute_API.c", __zend_lineno=439) at /home/glopes/php/php-5.3.2/Zend/zend_variables.c:52 #11 0x081e96cf in _zval_dtor (zvalue=0x841c45c, __zend_filename=0x83621b8 "/home/glopes/php/php-5.3.2/Zend/zend_execute_API.c", __zend_lineno=439) at /home/glopes/php/php-5.3.2/Zend/zend_variables.h:35 #12 0x081e9919 in _zval_ptr_dtor (zval_ptr=0x841d5d8, __zend_filename=0x83633a0 "/home/glopes/php/php-5.3.2/Zend/zend_variables.c", __zend_lineno=178) at /home/glopes/php/php-5.3.2/Zend/zend_execute_API.c:439 #13 0x081f7ca8 in _zval_ptr_dtor_wrapper (zval_ptr=0x841d5d8) at /home/glopes/php/php-5.3.2/Zend/zend_variables.c:178 #14 0x0820806e in zend_hash_apply_deleter (ht=0x83879d0, p=0x841d5cc) at /home/glopes/php/php-5.3.2/Zend/zend_hash.c:611 #15 0x08208596 in zend_hash_reverse_apply (ht=0x83879d0, apply_func=0x81e91bd <zval_call_destructor>) at /home/glopes/php/php-5.3.2/Zend/zend_hash.c:760 #16 0x081e924a in shutdown_destructors () at /home/glopes/php/php-5.3.2/Zend/zend_execute_API.c:226 #17 0x081f943c in zend_call_destructors () at /home/glopes/php/php-5.3.2/Zend/zend.c:874 #18 0x08190427 in php_request_shutdown (dummy=0x0) at /home/glopes/php/php-5.3.2/main/main.c:1587 #19 0x082c0086 in main (argc=2, argv=0xbfffe674) at /home/glopes/php/php-5.3.2/sapi/cli/php_cli.c:1373 ------------------------------------------------------------------------ -- Edit this bug report at http://bugs.php.net/bug.php?id=51768&edit=1