]> granicus.if.org Git - php/commitdiff
Fixed bugs #29767 and #31683 (__get and __set methods must not modify property name).
authorDmitry Stogov <dmitry@php.net>
Wed, 2 Feb 2005 07:19:22 +0000 (07:19 +0000)
committerDmitry Stogov <dmitry@php.net>
Wed, 2 Feb 2005 07:19:22 +0000 (07:19 +0000)
Zend/tests/bug31683.phpt [new file with mode: 0644]
Zend/zend.h
Zend/zend_object_handlers.c

diff --git a/Zend/tests/bug31683.phpt b/Zend/tests/bug31683.phpt
new file mode 100644 (file)
index 0000000..4e0159d
--- /dev/null
@@ -0,0 +1,97 @@
+--TEST--
+Bug #31683 (changes to $name in __get($name) override future parameters)
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+
+class Foo implements ArrayAccess {
+
+  function __get($test) {
+    var_dump($test);         
+    $test = 'bug';
+  }
+
+  function __set($test, $val) {
+    var_dump($test);         
+    var_dump($val);
+    $test = 'bug';
+    $val = 'bug';
+  }
+
+  function __call($test, $arg) {
+    var_dump($test);         
+    $test = 'bug';
+  }
+
+  function offsetget($test) {
+    var_dump($test);         
+    $test = 'bug';
+    return 123;
+  }
+
+  function offsetset($test, $val) {
+    var_dump($test);         
+    var_dump($val);         
+    $test = 'bug';
+    $val  = 'bug';
+  }
+
+  function offsetexists($test) {
+    var_dump($test);         
+    $test = 'bug';
+  }
+
+  function offsetunset($test) {
+    var_dump($test);         
+    $test = 'bug';
+  }
+
+}
+
+$foo = new Foo();
+$a = "ok";
+
+for ($i=0; $i < 2; $i++) {
+  $foo->ok("ok");
+  $foo->ok;
+  $foo->ok = "ok";
+  $x = $foo["ok"];
+  $foo["ok"] = "ok";
+  isset($foo["ok"]);
+  unset($foo["ok"]);
+//  $foo[];
+  $foo[] = "ok";
+//  isset($foo[]);
+//  unset($foo[]);
+  $foo->$a;
+  echo "---\n";
+}
+?>
+--EXPECT--
+string(2) "ok"
+string(2) "ok"
+string(2) "ok"
+string(2) "ok"
+string(2) "ok"
+string(2) "ok"
+string(2) "ok"
+string(2) "ok"
+string(2) "ok"
+NULL
+string(2) "ok"
+string(2) "ok"
+---
+string(2) "ok"
+string(2) "ok"
+string(2) "ok"
+string(2) "ok"
+string(2) "ok"
+string(2) "ok"
+string(2) "ok"
+string(2) "ok"
+string(2) "ok"
+NULL
+string(2) "ok"
+string(2) "ok"
+---
index 0ec9fd3c14ba9d747803ada5d1e36b67f10b9818..c9cb4852334948309e319bee58c6f568092a1067 100644 (file)
@@ -605,6 +605,20 @@ END_EXTERN_C()
        (*ppzv_dest)->refcount = refcount;                      \
 }
 
+#define SEPARATE_ARG_IF_REF(varptr) \
+       if (PZVAL_IS_REF(varptr)) { \
+               zval *original_var = varptr; \
+               ALLOC_ZVAL(varptr); \
+               varptr->value = original_var->value; \
+               varptr->type = original_var->type; \
+               varptr->is_ref = 0; \
+               varptr->refcount = 1; \
+               zval_copy_ctor(varptr); \
+       } else { \
+               varptr->refcount++; \
+       }
+
+
 #define ZEND_MAX_RESERVED_RESOURCES    4
 
 #include "zend_variables.h"
index f7e54e5a165632a5461b7915042af18ce949a24f..21f879adc1815e536f6ddd68868007b07d19561e 100644 (file)
@@ -66,8 +66,13 @@ static zval *zend_std_call_getter(zval *object, zval *member TSRMLS_DC)
 
           it should return whether the call was successfull or not
        */
+       
+       SEPARATE_ARG_IF_REF(member);
+
        zend_call_method_with_1_params(&object, ce, &ce->__get, ZEND_GET_FUNC_NAME, &retval, member);
 
+       zval_ptr_dtor(&member);
+
        if (retval) {
                retval->refcount--;
        }
@@ -80,7 +85,8 @@ static int zend_std_call_setter(zval *object, zval *member, zval *value TSRMLS_D
        zval *retval = NULL;
        int ret;
        zend_class_entry *ce = Z_OBJCE_P(object);
-       
+
+       SEPARATE_ARG_IF_REF(member);
        value->refcount++;
 
        /* __set handler is called with two arguments:
@@ -91,6 +97,7 @@ static int zend_std_call_setter(zval *object, zval *member, zval *value TSRMLS_D
        */
        zend_call_method_with_2_params(&object, ce, &ce->__set, ZEND_SET_FUNC_NAME, &retval, member, value);
 
+       zval_ptr_dtor(&member);
        zval_ptr_dtor(&value);
 
        if (retval && zend_is_true(retval)) {
@@ -334,12 +341,14 @@ zval *zend_std_read_dimension(zval *object, zval *offset, int type TSRMLS_DC)
        if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) {
                if(offset == NULL) {
                        /* [] construct */
-                       zval offset_null;
-                       INIT_ZVAL(offset_null);
-                       offset = &offset_null;
+                       ALLOC_INIT_ZVAL(offset);
+               } else {
+                       SEPARATE_ARG_IF_REF(offset);
                }
                zend_call_method_with_1_params(&object, ce, NULL, "offsetget", &retval, offset);
 
+               zval_ptr_dtor(&offset);
+
                if (!retval) {
                        if (!EG(exception)) {
                                zend_error(E_ERROR, "Undefined offset for object of type %s used as array", ce->name);
@@ -361,14 +370,15 @@ zval *zend_std_read_dimension(zval *object, zval *offset, int type TSRMLS_DC)
 static void zend_std_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC)
 {
        zend_class_entry *ce = Z_OBJCE_P(object);
-       zval tmp;
-       
+
        if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) {
                if (!offset) {
-                       INIT_ZVAL(tmp);
-                       offset = &tmp;
+                       ALLOC_INIT_ZVAL(offset);
+               } else {
+                       SEPARATE_ARG_IF_REF(offset);
                }
                zend_call_method_with_2_params(&object, ce, NULL, "offsetset", NULL, offset, value);
+               zval_ptr_dtor(&offset);
        } else {
                zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name);
        }
@@ -382,7 +392,9 @@ static int zend_std_has_dimension(zval *object, zval *offset, int check_empty TS
        int result;
        
        if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) {
+               SEPARATE_ARG_IF_REF(offset);
                zend_call_method_with_1_params(&object, ce, NULL, "offsetexists", &retval, offset);
+               zval_ptr_dtor(&offset);
                result = i_zend_is_true(retval);
                zval_ptr_dtor(&retval);
                return result;
@@ -467,7 +479,9 @@ static void zend_std_unset_dimension(zval *object, zval *offset TSRMLS_DC)
        zval *retval;
        
        if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) {
+               SEPARATE_ARG_IF_REF(offset);
                zend_call_method_with_1_params(&object, ce, NULL, "offsetunset", &retval, offset);
+               zval_ptr_dtor(&offset);
                zval_ptr_dtor(&retval);
        } else {
                zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name);