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
-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to