Edit report at https://bugs.php.net/bug.php?id=60701&edit=1
ID: 60701 Comment by: hans at rakers dot org Reported by: daan at react dot com Summary: __toString() which stores $this reference triggers segfault Status: Open Type: Bug Package: Class/Object related Operating System: CentOS PHP Version: 5.3.8 Block user comment: N Private report: N New Comment: This bug is caused by zend_std_cast_object_tostring() not checking the refcount of readobj when readobj==writeobj. It calls INIT_PZVAL(writeobj) without checking the refcount first, causing any further references to this zval to get corrupted (in this case, the 'test' property of StringableObject). My patch against 5.3 is attached. Previous Comments: ------------------------------------------------------------------------ [2012-01-10 19:22:39] sjon at hortensius dot net This bug is not reproducible when php is compiled with enable-debug. It is however reproducible in other PHP versions, such as 5.3.7/5.3.6/5.3.5 ------------------------------------------------------------------------ [2012-01-10 16:43:17] daan at react dot com Description: ------------ A simple object construction where a __toString() stores $this, will trigger a segfault during garbage collection at the end of the request. Probably related bug: https://bugs.php.net/bug.php?id=60598 Is a distilled version of this bug: https://bugs.php.net/bug.php?id=60457 Test script: --------------- <?php class Container { public function getObject() { $this->object = new StringableObject(); return $this->object; } // This destructor is required to exist to trigger the segfault public function __destruct() { } } class StringableObject { public function __toString() { $this->test = $this; return ''; } } $container = new Container(); $object = $container->getObject(); // Any kind of function which triggers a 'to string' object conversion // Casting $object with (string) will circumvent the problem echo trim($object); // Another call is required to corrupt heap echo trim('test'); Expected result: ---------------- test Actual result: -------------- Segfault gdb backtrace (with commandline PHP with build tag ZEND_DEBUG_OBJECTS) [Thread debugging using libthread_db enabled] Allocated object id #1 Allocated object id #2 Increased refcount of object id #2 Decreased refcount of object id #2 testIncreased refcount of object id #1 Decreased refcount of object id #1 Deallocated object id #1 Program received signal SIGSEGV, Segmentation fault. 0x00000000006d4c69 in gc_zval_possible_root (zv=0x1023e40) at /home/sjon/php- debug/php-5.3.8/Zend/zend_gc.c:143 143 GC_ZOBJ_CHECK_POSSIBLE_ROOT(zv); (gdb) bt #0 0x00000000006d4c69 in gc_zval_possible_root (zv=0x1023e40) at /home/sjon/php-debug/php-5.3.8/Zend/zend_gc.c:143 #1 0x00000000006c4ad8 in zend_hash_destroy (ht=0x10266d0) at /home/sjon/php- debug/php-5.3.8/Zend/zend_hash.c:529 #2 0x00000000006d6009 in zend_object_std_dtor (object=0x1023dc8) at /home/sjon/php-debug/php-5.3.8/Zend/zend_objects.c:45 #3 0x00000000006d6029 in zend_objects_free_object_storage (object=0x1023dc8) at /home/sjon/php-debug/php-5.3.8/Zend/zend_objects.c:126 #4 0x00000000006da037 in zend_objects_store_del_ref_by_handle_ex (handle=2, handlers=<optimized out>) at /home/sjon/php-debug/php- 5.3.8/Zend/zend_objects_API.c:220 #5 0x00000000006da053 in zend_objects_store_del_ref (zobject=0x1022350) at /home/sjon/php-debug/php-5.3.8/Zend/zend_objects_API.c:172 #6 0x00000000006a9571 in _zval_dtor (zvalue=0x1022350) at /home/sjon/php- debug/php-5.3.8/Zend/zend_variables.h:35 #7 _zval_ptr_dtor (zval_ptr=<optimized out>) at /home/sjon/php-debug/php- 5.3.8/Zend/zend_execute_API.c:447 #8 0x00000000006c3645 in zend_hash_apply_deleter (ht=0xe33188, p=0x1026728) at /home/sjon/php-debug/php-5.3.8/Zend/zend_hash.c:612 #9 0x00000000006c4f81 in zend_hash_reverse_apply (ht=0xe33188, apply_func=0x6a9430 <zval_call_destructor>) at /home/sjon/php-debug/php- 5.3.8/Zend/zend_hash.c:762 #10 0x00000000006a9921 in shutdown_destructors () at /home/sjon/php-debug/php- 5.3.8/Zend/zend_execute_API.c:226 #11 0x00000000006b7747 in zend_call_destructors () at /home/sjon/php-debug/php- 5.3.8/Zend/zend.c:875 #12 0x00000000006651fd in php_request_shutdown (dummy=<optimized out>) at /home/sjon/php-debug/php-5.3.8/main/main.c:1594 #13 0x000000000042d105 in main (argc=2, argv=0x7fffffffebb8) at /home/sjon/php- debug/php-5.3.8/sapi/cli/php_cli.c:1363 (gdb) frame 2 #2 0x00000000006d6009 in zend_object_std_dtor (object=0x1023dc8) at /home/sjon/php-debug/php-5.3.8/Zend/zend_objects.c:45 45 zend_hash_destroy(object->properties); (gdb) print object->ce->name $1 = 0x1025af0 "StringableObject" (gdb) frame 1 #1 0x00000000006c4ad8 in zend_hash_destroy (ht=0x10266d0) at /home/sjon/php- debug/php-5.3.8/Zend/zend_hash.c:529 529 ht->pDestructor(q->pData); (gdb) print_ht ht [0x010266d0] { "test\0" => [0x01023e40] (refcount=-1) object Program received signal SIGSEGV, Segmentation fault. 0x00000000006da0a4 in zend_object_store_get_object (zobject=0x1023e40) at /home/sjon/php-debug/php-5.3.8/Zend/zend_objects_API.c:272 272 return EG(objects_store).object_buckets[handle].bucket.obj.object; The program being debugged was signaled while in a function called from GDB. GDB remains in the frame where the signal was received. To change this behavior use "set unwindonsignal on". Evaluation of the expression containing the function (zend_objects_get_address) will be abandoned. When the function is done executing, GDB will silently stop. (gdb) ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=60701&edit=1