]> granicus.if.org Git - php/commitdiff
Fixed indirect modification of magic ArrayAccess method arguments
authorDmitry Stogov <dmitry@zend.com>
Thu, 26 Oct 2017 13:03:42 +0000 (16:03 +0300)
committerDmitry Stogov <dmitry@zend.com>
Thu, 26 Oct 2017 13:03:42 +0000 (16:03 +0300)
Zend/tests/bug75420.10.phpt [new file with mode: 0644]
Zend/tests/bug75420.11.phpt [new file with mode: 0644]
Zend/tests/bug75420.12.phpt [new file with mode: 0644]
Zend/tests/bug75420.13.phpt [new file with mode: 0644]
Zend/tests/bug75420.14.phpt [new file with mode: 0644]
Zend/tests/bug75420.15.phpt [new file with mode: 0644]
Zend/tests/bug75420.16.phpt [new file with mode: 0644]
Zend/tests/bug75420.9.phpt [new file with mode: 0644]
Zend/zend_object_handlers.c

diff --git a/Zend/tests/bug75420.10.phpt b/Zend/tests/bug75420.10.phpt
new file mode 100644 (file)
index 0000000..c2ae3aa
--- /dev/null
@@ -0,0 +1,21 @@
+--TEST--
+Bug #75420.10 (Indirect modification of magic method argument)
+--FILE--
+<?php
+class Test implements ArrayAccess {
+       public function offsetExists($x) { $GLOBALS["name"] = 24; return true; }
+       public function offsetGet($x) { var_dump($x); return 42; }
+       public function offsetSet($x, $y) { }
+       public function offsetUnset($x) { }
+}
+
+$obj = new Test;
+$name = "foo";
+$name = str_repeat($name, 2);
+var_dump($obj[$name] ?? 12);
+var_dump($name);
+?>
+--EXPECT--
+string(6) "foofoo"
+int(42)
+int(24)
diff --git a/Zend/tests/bug75420.11.phpt b/Zend/tests/bug75420.11.phpt
new file mode 100644 (file)
index 0000000..1ec623e
--- /dev/null
@@ -0,0 +1,20 @@
+--TEST--
+Bug #75420.11 (Indirect modification of magic method argument)
+--FILE--
+<?php
+class Test implements ArrayAccess {
+       public function offsetExists($x) { $GLOBALS["name"] = 24; return true; }
+       public function offsetGet($x) { var_dump($x); return 42; }
+       public function offsetSet($x, $y) { }
+       public function offsetUnset($x) { }
+}
+
+$obj = new Test;
+$name = "foo";
+var_dump(empty($obj[$name]));
+var_dump($name);
+?>
+--EXPECT--
+string(3) "foo"
+bool(false)
+int(24)
diff --git a/Zend/tests/bug75420.12.phpt b/Zend/tests/bug75420.12.phpt
new file mode 100644 (file)
index 0000000..7ed6f14
--- /dev/null
@@ -0,0 +1,21 @@
+--TEST--
+Bug #75420.12 (Indirect modification of magic method argument)
+--FILE--
+<?php
+class Test implements ArrayAccess {
+       public function offsetExists($x) { $GLOBALS["name"] = 24; return true; }
+       public function offsetGet($x) { var_dump($x); return 42; }
+       public function offsetSet($x, $y) { }
+       public function offsetUnset($x) { }
+}
+
+$obj = new Test;
+$name = "foo";
+$name = str_repeat($name, 2);
+var_dump(empty($obj[$name]));
+var_dump($name);
+?>
+--EXPECT--
+string(6) "foofoo"
+bool(false)
+int(24)
diff --git a/Zend/tests/bug75420.13.phpt b/Zend/tests/bug75420.13.phpt
new file mode 100644 (file)
index 0000000..38031ba
--- /dev/null
@@ -0,0 +1,20 @@
+--TEST--
+Bug #75420.13 (Indirect modification of magic method argument)
+--FILE--
+<?php
+class Test implements ArrayAccess {
+       public function offsetExists($x) { $GLOBALS["obj"] = 24; return true; }
+       public function offsetGet($x) { var_dump($x); return 42; }
+       public function offsetSet($x, $y) { }
+       public function offsetUnset($x) { }
+}
+
+$obj = new Test;
+$name = "foo";
+var_dump($obj[$name] ?? 12);
+var_dump($obj);
+?>
+--EXPECT--
+string(3) "foo"
+int(42)
+int(24)
diff --git a/Zend/tests/bug75420.14.phpt b/Zend/tests/bug75420.14.phpt
new file mode 100644 (file)
index 0000000..07fb2cd
--- /dev/null
@@ -0,0 +1,20 @@
+--TEST--
+Bug #75420.14 (Indirect modification of magic method argument)
+--FILE--
+<?php
+class Test implements ArrayAccess {
+       public function offsetExists($x) { $GLOBALS["obj"] = 24; return true; }
+       public function offsetGet($x) { var_dump($x); return 42; }
+       public function offsetSet($x, $y) { }
+       public function offsetUnset($x) { }
+}
+
+$obj = new Test;
+$name = "foo";
+var_dump(empty($obj[$name]));
+var_dump($obj);
+?>
+--EXPECT--
+string(3) "foo"
+bool(false)
+int(24)
diff --git a/Zend/tests/bug75420.15.phpt b/Zend/tests/bug75420.15.phpt
new file mode 100644 (file)
index 0000000..f747b4c
--- /dev/null
@@ -0,0 +1,20 @@
+--TEST--
+Bug #75420.15 (Indirect modification of magic method argument)
+--FILE--
+<?php
+class Test implements ArrayAccess {
+       public function offsetExists($x) { }
+       public function offsetGet($x) { }
+       public function offsetSet($x, $y) { $GLOBALS["name"] = 24; var_dump($x); }
+       public function offsetUnset($x) { }
+}
+
+$obj = new Test;
+$name = "foo";
+$name = str_repeat($name, 2);
+$obj[$name] = 1;
+var_dump($name);
+?>
+--EXPECT--
+string(6) "foofoo"
+int(24)
diff --git a/Zend/tests/bug75420.16.phpt b/Zend/tests/bug75420.16.phpt
new file mode 100644 (file)
index 0000000..6c3982e
--- /dev/null
@@ -0,0 +1,20 @@
+--TEST--
+Bug #75420.16 (Indirect modification of magic method argument)
+--FILE--
+<?php
+class Test implements ArrayAccess {
+       public function offsetExists($x) { }
+       public function offsetGet($x) { }
+       public function offsetSet($x, $y) { $GLOBALS["obj"] = 24; var_dump($this); }
+       public function offsetUnset($x) { }
+}
+
+$obj = new Test;
+$name = "foo";
+$obj[$name] = 1;
+var_dump($obj);
+?>
+--EXPECT--
+object(Test)#1 (0) {
+}
+int(24)
diff --git a/Zend/tests/bug75420.9.phpt b/Zend/tests/bug75420.9.phpt
new file mode 100644 (file)
index 0000000..d83878e
--- /dev/null
@@ -0,0 +1,20 @@
+--TEST--
+Bug #75420.9 (Indirect modification of magic method argument)
+--FILE--
+<?php
+class Test implements ArrayAccess {
+       public function offsetExists($x) { $GLOBALS["name"] = 24; return true; }
+       public function offsetGet($x) { var_dump($x); return 42; }
+       public function offsetSet($x, $y) { }
+       public function offsetUnset($x) { }
+}
+
+$obj = new Test;
+$name = "foo";
+var_dump($obj[$name] ?? 12);
+var_dump($name);
+?>
+--EXPECT--
+string(3) "foo"
+int(42)
+int(24)
index 8028b2ee5b46d4b8c00a92f98cf6d85a461557fc..3b86a1a6ebce2e83092a48f0a235449eebd31a1a 100644 (file)
@@ -734,34 +734,38 @@ exit:
 zval *zend_std_read_dimension(zval *object, zval *offset, int type, zval *rv) /* {{{ */
 {
        zend_class_entry *ce = Z_OBJCE_P(object);
-       zval tmp;
+       zval tmp_offset, tmp_object;
 
        if (EXPECTED(instanceof_function_ex(ce, zend_ce_arrayaccess, 1) != 0)) {
                if (offset == NULL) {
                        /* [] construct */
-                       ZVAL_NULL(&tmp);
-                       offset = &tmp;
+                       ZVAL_NULL(&tmp_offset);
                } else {
-                       SEPARATE_ARG_IF_REF(offset);
+                       ZVAL_DEREF(offset);
+                       ZVAL_COPY(&tmp_offset, offset);
                }
 
+               ZVAL_COPY(&tmp_object, object);
                if (type == BP_VAR_IS) {
-                       zend_call_method_with_1_params(object, ce, NULL, "offsetexists", rv, offset);
+                       zend_call_method_with_1_params(&tmp_object, ce, NULL, "offsetexists", rv, &tmp_offset);
                        if (UNEXPECTED(Z_ISUNDEF_P(rv))) {
-                               zval_ptr_dtor(offset);
+                               zval_ptr_dtor(&tmp_object);
+                               zval_ptr_dtor(&tmp_offset);
                                return NULL;
                        }
                        if (!i_zend_is_true(rv)) {
-                               zval_ptr_dtor(offset);
+                               zval_ptr_dtor(&tmp_object);
+                               zval_ptr_dtor(&tmp_offset);
                                zval_ptr_dtor(rv);
                                return &EG(uninitialized_zval);
                        }
                        zval_ptr_dtor(rv);
                }
 
-               zend_call_method_with_1_params(object, ce, NULL, "offsetget", rv, offset);
+               zend_call_method_with_1_params(&tmp_object, ce, NULL, "offsetget", rv, &tmp_offset);
 
-               zval_ptr_dtor(offset);
+               zval_ptr_dtor(&tmp_object);
+               zval_ptr_dtor(&tmp_offset);
 
                if (UNEXPECTED(Z_TYPE_P(rv) == IS_UNDEF)) {
                        if (UNEXPECTED(!EG(exception))) {
@@ -780,17 +784,19 @@ zval *zend_std_read_dimension(zval *object, zval *offset, int type, zval *rv) /*
 static void zend_std_write_dimension(zval *object, zval *offset, zval *value) /* {{{ */
 {
        zend_class_entry *ce = Z_OBJCE_P(object);
-       zval tmp;
+       zval tmp_offset, tmp_object;
 
        if (EXPECTED(instanceof_function_ex(ce, zend_ce_arrayaccess, 1) != 0)) {
                if (!offset) {
-                       ZVAL_NULL(&tmp);
-                       offset = &tmp;
+                       ZVAL_NULL(&tmp_offset);
                } else {
-                       SEPARATE_ARG_IF_REF(offset);
+                       ZVAL_DEREF(offset);
+                       ZVAL_COPY(&tmp_offset, offset);
                }
-               zend_call_method_with_2_params(object, ce, NULL, "offsetset", NULL, offset, value);
-               zval_ptr_dtor(offset);
+               ZVAL_COPY(&tmp_object, object);
+               zend_call_method_with_2_params(&tmp_object, ce, NULL, "offsetset", NULL, &tmp_offset, value);
+               zval_ptr_dtor(&tmp_object);
+               zval_ptr_dtor(&tmp_offset);
        } else {
                zend_throw_error(NULL, "Cannot use object of type %s as array", ZSTR_VAL(ce->name));
        }
@@ -800,17 +806,19 @@ static void zend_std_write_dimension(zval *object, zval *offset, zval *value) /*
 static int zend_std_has_dimension(zval *object, zval *offset, int check_empty) /* {{{ */
 {
        zend_class_entry *ce = Z_OBJCE_P(object);
-       zval retval;
+       zval retval, tmp_offset, tmp_object;
        int result;
 
        if (EXPECTED(instanceof_function_ex(ce, zend_ce_arrayaccess, 1) != 0)) {
-               SEPARATE_ARG_IF_REF(offset);
-               zend_call_method_with_1_params(object, ce, NULL, "offsetexists", &retval, offset);
+               ZVAL_DEREF(offset);
+               ZVAL_COPY(&tmp_offset, offset);
+               ZVAL_COPY(&tmp_object, object);
+               zend_call_method_with_1_params(&tmp_object, ce, NULL, "offsetexists", &retval, &tmp_offset);
                if (EXPECTED(Z_TYPE(retval) != IS_UNDEF)) {
                        result = i_zend_is_true(&retval);
                        zval_ptr_dtor(&retval);
                        if (check_empty && result && EXPECTED(!EG(exception))) {
-                               zend_call_method_with_1_params(object, ce, NULL, "offsetget", &retval, offset);
+                               zend_call_method_with_1_params(&tmp_object, ce, NULL, "offsetget", &retval, &tmp_offset);
                                if (EXPECTED(Z_TYPE(retval) != IS_UNDEF)) {
                                        result = i_zend_is_true(&retval);
                                        zval_ptr_dtor(&retval);
@@ -819,7 +827,8 @@ static int zend_std_has_dimension(zval *object, zval *offset, int check_empty) /
                } else {
                        result = 0;
                }
-               zval_ptr_dtor(offset);
+               zval_ptr_dtor(&tmp_object);
+               zval_ptr_dtor(&tmp_offset);
        } else {
                zend_throw_error(NULL, "Cannot use object of type %s as array", ZSTR_VAL(ce->name));
                return 0;
@@ -981,11 +990,15 @@ exit:
 static void zend_std_unset_dimension(zval *object, zval *offset) /* {{{ */
 {
        zend_class_entry *ce = Z_OBJCE_P(object);
+       zval tmp_offset, tmp_object;
 
        if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1)) {
-               SEPARATE_ARG_IF_REF(offset);
-               zend_call_method_with_1_params(object, ce, NULL, "offsetunset", NULL, offset);
-               zval_ptr_dtor(offset);
+               ZVAL_DEREF(offset);
+               ZVAL_COPY(&tmp_offset, offset);
+               ZVAL_COPY(&tmp_object, object);
+               zend_call_method_with_1_params(&tmp_object, ce, NULL, "offsetunset", NULL, &tmp_offset);
+               zval_ptr_dtor(&tmp_object);
+               zval_ptr_dtor(&tmp_offset);
        } else {
                zend_throw_error(NULL, "Cannot use object of type %s as array", ZSTR_VAL(ce->name));
        }