Fix for bug #37667

From: Date: Fri, 02 Jun 2006 23:28:30 +0000
Subject: Fix for bug #37667
Groups: php.internals 
Request: Send a blank email to internals+get-23872@lists.php.net to get a copy of this message
Hello internals, Bug #37667 describes a problem with returning an array from __get() in write context. <?php class Class1 { var $property = array(); function getProperty() { return $this->property; } } $c = new Class1(); $d = & $c->getProperty(); $d[] = 1; var_dump($c); ?> The engine sees the read to the array property as a write no matter whether it is a read or write operation. I think we should pass the correct mode and then in the get_property handler use the info to protect against writing to a returned array since reading it is pretty fine of course. Right now we use the access type only to silence warnings in case of BP_VAR_IS. No further distincion is done using the access type. So i patched the necessary changes into my HEAD and also verified that the patch does not affect any test case. So it seems quite good. But i do not want to decide here since it is a) a change of behavior and b) it introduces a new error message. Now with the patch applied the above code will result in the following error message: Fatal error: Cannot use array returned from Test::__get('property') in write context in %sbug37667.php on line %d Comments? Best regards, Marcus

Index: Zend/zend_execute.c =================================================================== RCS file: /repository/ZendEngine2/zend_execute.c,v retrieving revision 1.746 diff -u -p -d -r1.746 zend_execute.c --- Zend/zend_execute.c 1 Jun 2006 11:56:23 -0000 1.746 +++ Zend/zend_execute.c 2 Jun 2006 23:05:45 -0000 @@ -1272,7 +1272,7 @@ static void zend_fetch_property_address( zval *ptr; if (Z_OBJ_HT_P(container)->read_property && - (ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, BP_VAR_W TSRMLS_CC)) != NULL) { + (ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type TSRMLS_CC)) != NULL) { if (result) { result->var.ptr = ptr; result->var.ptr_ptr = &result->var.ptr; @@ -1285,7 +1285,7 @@ static void zend_fetch_property_address( } } else if (Z_OBJ_HT_P(container)->read_property) { if (result) { - result->var.ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, BP_VAR_W TSRMLS_CC); + result->var.ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type TSRMLS_CC); result->var.ptr_ptr = &result->var.ptr; } } else { Index: Zend/zend_object_handlers.c =================================================================== RCS file: /repository/ZendEngine2/zend_object_handlers.c,v retrieving revision 1.167 diff -u -p -d -r1.167 zend_object_handlers.c --- Zend/zend_object_handlers.c 29 May 2006 19:57:43 -0000 1.167 +++ Zend/zend_object_handlers.c 2 Jun 2006 23:05:46 -0000 @@ -357,6 +357,9 @@ zval *zend_std_read_property(zval *objec zval_ptr_dtor(&tmp_member); (*retval)->refcount--; } + if (*retval && (type == BP_VAR_W || type == BP_VAR_RW) && Z_TYPE_PP(retval) == IS_ARRAY) { + zend_error(E_ERROR, "Cannot use array returned from %v::__get('%R') in write context", zobj->ce->name, Z_TYPE_P(member), Z_STRVAL_P(member)); + } return *retval; } Index: Zend/tests/bug37667.phpt =================================================================== RCS file: Zend/tests/bug37667.phpt diff -N Zend/tests/bug37667.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/bug37667.phpt 2 Jun 2006 23:05:46 -0000 @@ -0,0 +1,57 @@ +--TEST-- +#37667 (Object is not added into array returned by __get) +--FILE-- +<?php + +class Test +{ + protected $property = array('foo' => 'bar'); + + function __get($name) + { + return $this->property; + } +} + +$obj = new Test; + +var_dump($obj->property['foo']); +var_dump($obj->property[2]); + +var_dump($obj); + +$obj->property[] = 1; +$obj->property[] = 2; + +var_dump($obj); + +?> +===DONE=== +--EXPECTF-- +string(3) "bar" + +Notice: Undefined offset: 2 in %sbug37667.php on line %d +NULL +object(Test)#%d (1) { + ["property":protected]=> + array(1) { + ["foo"]=> + string(3) "bar" + } +} + +Fatal error: Cannot use array returned from Test::__get('property') in write context in %sbug37667.php on line %d +--UEXPECTF-- +unicode(3) "bar" + +Notice: Undefined offset: 2 in %sbug37667.php on line %d +NULL +object(Test)#%d (1) { + [u"property":protected]=> + array(1) { + [u"foo"]=> + unicode(3) "bar" + } +} + +Fatal error: Cannot use array returned from Test::__get('property') in write context in %sbug37667.php on line %d
« previous php.internals (#23872) next »