php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #52772 var_dump() doesn't check for the existence of get_class_name before calling it
Submitted: 2010-09-04 03:03 UTC Modified: 2010-09-13 22:14 UTC
From: cataphract@php.net Assigned: kalle
Status: Closed Package: Variables related
PHP Version: trunk-SVN-2010-09-04 (snap) OS: Windows
Private report: No CVE-ID:
 [2010-09-04 03:03 UTC] 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


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2010-09-13 22:14 UTC] kalle@php.net
Automatic comment from SVN on behalf of kalle
Revision: http://svn.php.net/viewvc/?view=revision&amp;revision=303330
Log: Fixed bug #52772 (var_dump() doesn't check for the existence of get_class_name before calling it)
 [2010-09-13 22:14 UTC] kalle@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: kalle
 [2010-09-13 22:14 UTC] kalle@php.net
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 :)
 [2010-09-13 23:54 UTC] pajoye@php.net
Automatic comment from SVN on behalf of pajoye
Revision: http://svn.php.net/viewvc/?view=revision&amp;revision=303332
Log: - fix build introduced by fix for #52772
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Wed Apr 23 07:02:14 2014 UTC