diff options
-rw-r--r-- | Zend/tests/bug75420.1.phpt | 18 | ||||
-rw-r--r-- | Zend/tests/bug75420.2.phpt | 20 | ||||
-rw-r--r-- | Zend/tests/bug75420.3.phpt | 18 | ||||
-rw-r--r-- | Zend/tests/bug75420.4.phpt | 17 | ||||
-rw-r--r-- | Zend/tests/bug75420.5.phpt | 19 | ||||
-rw-r--r-- | Zend/tests/bug75420.6.phpt | 19 | ||||
-rw-r--r-- | Zend/tests/bug75420.phpt | 2 | ||||
-rw-r--r-- | Zend/zend_object_handlers.c | 33 |
8 files changed, 140 insertions, 6 deletions
diff --git a/Zend/tests/bug75420.1.phpt b/Zend/tests/bug75420.1.phpt new file mode 100644 index 0000000000..80e951ac9e --- /dev/null +++ b/Zend/tests/bug75420.1.phpt @@ -0,0 +1,18 @@ +--TEST-- +Bug #75420.1 (Indirect modification of magic method argument) +--FILE-- +<?php +class Test { + public function __isset($x) { $GLOBALS["name"] = 24; return true; } + public function __get($x) { var_dump($x); return 42; } +} + +$obj = new Test; +$name = "foo"; +var_dump($obj->$name ?? 12); +var_dump($name); +?> +--EXPECT-- +string(3) "foo" +int(42) +int(24) diff --git a/Zend/tests/bug75420.2.phpt b/Zend/tests/bug75420.2.phpt new file mode 100644 index 0000000000..3e7a63ffed --- /dev/null +++ b/Zend/tests/bug75420.2.phpt @@ -0,0 +1,20 @@ +--TEST-- +Bug #75420.2 (Indirect modification of magic method argument) +--FILE-- +<?php +class Test { + public function __isset($x) { $GLOBALS["name"] = 24; return true; } + public function __get($x) { var_dump($x); return 42; } +} + +$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.3.phpt b/Zend/tests/bug75420.3.phpt new file mode 100644 index 0000000000..4810618d15 --- /dev/null +++ b/Zend/tests/bug75420.3.phpt @@ -0,0 +1,18 @@ +--TEST-- +Bug #75420.3 (Indirect modification of magic method argument) +--FILE-- +<?php +class Test { + public function __isset($x) { $GLOBALS["name"] = 24; return true; } + public function __get($x) { var_dump($x); return 42; } +} + +$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.4.phpt b/Zend/tests/bug75420.4.phpt new file mode 100644 index 0000000000..e25bf313cb --- /dev/null +++ b/Zend/tests/bug75420.4.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #75420.4 (Indirect modification of magic method argument) +--FILE-- +<?php +class Test { + public function __isset($x) { $GLOBALS["name"] = 24; return true; } + public function __get($x) { var_dump($x); return 42; } +} + +$obj = new Test; +$name = "foo"; +$name = str_repeat($name, 2); +var_dump(empty($obj->$name)); +?> +--EXPECT-- +string(6) "foofoo" +bool(false) diff --git a/Zend/tests/bug75420.5.phpt b/Zend/tests/bug75420.5.phpt new file mode 100644 index 0000000000..85fedc4679 --- /dev/null +++ b/Zend/tests/bug75420.5.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug #75420.5 (Indirect modification of magic method argument) +--FILE-- +<?php +class Test { + public function __isset($x) { $GLOBALS["obj"] = 24; return true; } + public function __get($x) { var_dump($this); return 42; } +} + +$obj = new Test; +$name = "foo"; +var_dump($obj->$name ?? 12); +var_dump($obj); +?> +--EXPECT-- +object(Test)#1 (0) { +} +int(42) +int(24) diff --git a/Zend/tests/bug75420.6.phpt b/Zend/tests/bug75420.6.phpt new file mode 100644 index 0000000000..e4aa230b48 --- /dev/null +++ b/Zend/tests/bug75420.6.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug #75420.6 (Indirect modification of magic method argument) +--FILE-- +<?php +class Test { + public function __isset($x) { $GLOBALS["obj"] = 24; return true; } + public function __get($x) { var_dump($this); return 42; } +} + +$obj = new Test; +$name = "foo"; +var_dump(empty($obj->$name)); +var_dump($obj); +?> +--EXPECT-- +object(Test)#1 (0) { +} +bool(false) +int(24) diff --git a/Zend/tests/bug75420.phpt b/Zend/tests/bug75420.phpt index 969a4a0417..5528ad301b 100644 --- a/Zend/tests/bug75420.phpt +++ b/Zend/tests/bug75420.phpt @@ -13,5 +13,5 @@ $name = "foo"; var_dump($obj->$name ?? 12); ?> --EXPECT-- -int(24) +string(3) "foo" int(42) diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index ff8ee732e9..0097f45b87 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -542,7 +542,7 @@ ZEND_API uint32_t *zend_get_property_guard(zend_object *zobj, zend_string *membe zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv) /* {{{ */ { zend_object *zobj; - zval tmp_member; + zval tmp_member, tmp_object; zval *retval; uintptr_t property_offset; uint32_t *guard = NULL; @@ -602,20 +602,28 @@ zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_ goto exit; } + ZVAL_UNDEF(&tmp_object); + /* magic isset */ if ((type == BP_VAR_IS) && zobj->ce->__isset) { zval tmp_result; guard = zend_get_property_guard(zobj, Z_STR_P(member)); if (!((*guard) & IN_ISSET)) { + if (Z_TYPE(tmp_member) == IS_UNDEF) { + ZVAL_COPY(&tmp_member, member); + member = &tmp_member; + } + ZVAL_COPY(&tmp_object, object); ZVAL_UNDEF(&tmp_result); *guard |= IN_ISSET; - zend_std_call_issetter(object, member, &tmp_result); + zend_std_call_issetter(&tmp_object, member, &tmp_result); *guard &= ~IN_ISSET; if (!zend_is_true(&tmp_result)) { retval = &EG(uninitialized_zval); + zval_ptr_dtor(&tmp_object); zval_ptr_dtor(&tmp_result); goto exit; } @@ -631,8 +639,11 @@ zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_ } if (!((*guard) & IN_GET)) { /* have getter - try with it! */ + if (Z_TYPE(tmp_object) == IS_UNDEF) { + ZVAL_COPY(&tmp_object, object); + } *guard |= IN_GET; /* prevent circular getting */ - zend_std_call_getter(object, member, rv); + zend_std_call_getter(&tmp_object, member, rv); *guard &= ~IN_GET; if (Z_TYPE_P(rv) != IS_UNDEF) { @@ -647,15 +658,20 @@ zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_ } else { retval = &EG(uninitialized_zval); } + zval_ptr_dtor(&tmp_object); goto exit; } else { if (Z_STRVAL_P(member)[0] == '\0' && Z_STRLEN_P(member) != 0) { + zval_ptr_dtor(&tmp_object); zend_throw_error(NULL, "Cannot access property started with '\\0'"); retval = &EG(uninitialized_zval); goto exit; } } } + + zval_ptr_dtor(&tmp_object); + if ((type != BP_VAR_IS)) { zend_error(E_NOTICE,"Undefined property: %s::$%s", ZSTR_VAL(zobj->ce->name), Z_STRVAL_P(member)); } @@ -1570,17 +1586,23 @@ found: if (!((*guard) & IN_ISSET)) { zval rv; + zval tmp_object; /* have issetter - try with it! */ + if (Z_TYPE(tmp_member) == IS_UNDEF) { + ZVAL_COPY(&tmp_member, member); + member = &tmp_member; + } + ZVAL_COPY(&tmp_object, object); (*guard) |= IN_ISSET; /* prevent circular getting */ - zend_std_call_issetter(object, member, &rv); + zend_std_call_issetter(&tmp_object, member, &rv); if (Z_TYPE(rv) != IS_UNDEF) { result = zend_is_true(&rv); zval_ptr_dtor(&rv); if (has_set_exists && result) { if (EXPECTED(!EG(exception)) && zobj->ce->__get && !((*guard) & IN_GET)) { (*guard) |= IN_GET; - zend_std_call_getter(object, member, &rv); + zend_std_call_getter(&tmp_object, member, &rv); (*guard) &= ~IN_GET; if (Z_TYPE(rv) != IS_UNDEF) { result = i_zend_is_true(&rv); @@ -1594,6 +1616,7 @@ found: } } (*guard) &= ~IN_ISSET; + zval_ptr_dtor(&tmp_object); } } |