Edit report at http://bugs.php.net/bug.php?id=52772&edit=1
ID: 52772 Updated by: ka...@php.net Reported by: cataphr...@php.net Summary: var_dump() doesn't check for the existence of get_class_name before calling it -Status: Open +Status: Closed Type: Bug Package: Variables related Operating System: Windows PHP Version: trunk-SVN-2010-09-04 (snap) -Assigned To: +Assigned To: kalle Block user comment: N New Comment: This bug has been fixed in SVN. Snapshots of the sources are packaged every three hours; this change will be in the next snapshot. You can grab the snapshot at http://snaps.php.net/. Thank you for the report, and for helping us make PHP better. Fixed in 5.2, 5.3 and trunk :) Previous Comments: ------------------------------------------------------------------------ [2010-09-13 22:14:20] ka...@php.net Automatic comment from SVN on behalf of kalle Revision: http://svn.php.net/viewvc/?view=revision&revision=303330 Log: Fixed bug #52772 (var_dump() doesn't check for the existence of get_class_name before calling it) ------------------------------------------------------------------------ [2010-09-04 03:03:08] cataphr...@php.net Description: ------------ php_var_dump has a NULL pointer dereference in var.c:136 Z_OBJ_HANDLER(**struc, get_class_name)(*struc, &class_name, &class_name_len, 0 TSRMLS_CC); It doesn't check the existence of the handler get_class_name before calling. In particular, it will crash when given a proxy object. The engine always checks for the existence of this handler before calling. See e.g. the definitions of ZEND_FUNCTION(get_parent_class) and zend_print_flat_zval_r: http://lxr.php.net/search?q=%22ZEND_FUNCTION%28get_parent_class%29%22&project=PHP_TRUNK&defs=&refs=&path=&hist= http://lxr.php.net/search?q=zend_print_flat_zval_r&project=PHP_TRUNK&defs=&refs=&path=&hist= Test script: --------------- /* Extension */ typedef struct _proxy_test { zend_object std; long value; } proxy_test; static zend_class_entry *pt_ce_ptr; static zend_object_handlers p_obj_handlers; static zend_object_value p_ce_create_object(zend_class_entry *class_type TSRMLS_DC) { zend_object_value zov; proxy_test *pobj; pobj = emalloc(sizeof *pobj); zend_object_std_init((zend_object *) pobj, class_type TSRMLS_CC); pobj->value = 7; object_properties_init(&pobj->std, class_type); zov.handle = zend_objects_store_put(pobj, (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 = &p_obj_handlers; return zov; } zval *p_read_property(zval *object, zval *member, int type, const struct _zend_literal *key TSRMLS_DC) { proxy_test *iobj = zend_object_store_get_object(object TSRMLS_CC); if (type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET) { zval *ret = zend_object_create_proxy(object, member TSRMLS_CC); Z_DELREF_P(ret); return ret; } else { zval *ret; MAKE_STD_ZVAL(ret); ZVAL_LONG(ret, iobj->value); Z_DELREF_P(ret); return ret; } } void p_write_property(zval *object, zval *member, zval *value, const struct _zend_literal *key TSRMLS_DC) { proxy_test *iobj = zend_object_store_get_object(object TSRMLS_CC); if (Z_TYPE_P(value) == IS_LONG) { iobj->value = Z_LVAL_P(value); } } zval **p_get_property_ptr_ptr(zval *object, zval *member, const struct _zend_literal *key TSRMLS_DC) { return NULL; } /*static zend_function_entry proxy_test_methods[] = { {NULL, NULL, NULL, 0, 0} };*/ ZEND_MODULE_STARTUP_D(testext) { zend_class_entry ce; INIT_CLASS_ENTRY(ce, "ProxyTestClass", NULL); pt_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC); pt_ce_ptr->create_object = p_ce_create_object; memcpy(&p_obj_handlers, zend_get_std_object_handlers(), sizeof p_obj_handlers); /* could be NULL, but an empty impl is better (see bug #51768) */ p_obj_handlers.get_property_ptr_ptr = p_get_property_ptr_ptr; p_obj_handlers.read_property = p_read_property; p_obj_handlers.write_property = p_write_property; } /* Script */ <?php $n = new ProxyTestClass(); $h =& $n->whatever; var_dump($h); NULL-pointer dereference on handler get_class_name Expected result: ---------------- No crash. Possibly, var_dump could show "proxy object" and show the zval returned by the get handler or it could just fail. Actual result: -------------- 00000000() > php5ts_debug.dll!php_var_dump(_zval_struct * * struc=0x010a22a8, int level=1, void * * * tsrm_ls=0x00fc4bf8) Line 136 + 0x23 bytes C php5ts_debug.dll!zif_var_dump(int ht=1, _zval_struct * return_value=0x010bf3f0, _zval_struct * * return_value_ptr=0x00000000, _zval_struct * this_ptr=0x00000000, int return_value_used=0, void * * * tsrm_ls=0x00fc4bf8) Line 181 + 0x15 bytes C php5ts_debug.dll!zend_do_fcall_common_helper_SPEC(_zend_execute_data * execute_data=0x010a20d8, void * * * tsrm_ls=0x00fc4bf8) Line 638 + 0x5f bytes C php5ts_debug.dll!ZEND_DO_FCALL_SPEC_CONST_HANDLER(_zend_execute_data * execute_data=0x010a20d8, void * * * tsrm_ls=0x00fc4bf8) Line 2018 C php5ts_debug.dll!execute(_zend_op_array * op_array=0x010c0dc8, void * * * tsrm_ls=0x00fc4bf8) Line 410 + 0x11 bytes C php5ts_debug.dll!zend_execute_scripts(int type=8, void * * * tsrm_ls=0x00fc4bf8, _zval_struct * * retval=0x00000000, int file_count=3, ...) Line 1193 + 0x21 bytes C php5ts_debug.dll!php_execute_script(_zend_file_handle * primary_file=0x0095fb48, void * * * tsrm_ls=0x00fc4bf8) Line 2330 + 0x1b bytes C php.exe!main(int argc=2, char * * argv=0x00fc4af8) Line 1252 + 0x13 bytes C php.exe!__tmainCRTStartup() Line 555 + 0x19 bytes C php.exe!mainCRTStartup() Line 371 C ------------------------------------------------------------------------ -- Edit this bug report at http://bugs.php.net/bug.php?id=52772&edit=1