Bug #52772 [Opn->Csd]: var_dump() doesn't check for the existence of get_class_name before calling it
| From: | kalle@php.net | Date: | Mon, 13 Sep 2010 20:14:50 +0000 |
| Subject: | Bug #52772 [Opn->Csd]: var_dump() doesn't check for the existence of get_class_name before calling it | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-154307@lists.php.net to get a copy of this message | ||
Edit report at http://bugs.php.net/bug.php?id=52772&edit=1
ID: 52772
Updated by: kalle@php.net
Reported by: cataphract@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] kalle@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] cataphract@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