Fixed indirect modification of magic method arguments.

This commit is contained in:
Dmitry Stogov 2017-10-26 13:05:23 +03:00
parent eaeccc1d99
commit bc59289b7a
8 changed files with 131 additions and 7 deletions

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -13,5 +13,5 @@ $name = "foo";
var_dump($obj->$name ?? 12); var_dump($obj->$name ?? 12);
?> ?>
--EXPECT-- --EXPECT--
int(24) string(3) "foo"
int(42) int(42)

View file

@ -507,7 +507,7 @@ static zend_long *zend_get_property_guard(zend_object *zobj, zend_string *member
zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv) /* {{{ */ zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv) /* {{{ */
{ {
zend_object *zobj; zend_object *zobj;
zval tmp_member; zval tmp_member, tmp_object;
zval *retval; zval *retval;
uint32_t property_offset; uint32_t property_offset;
zend_long *guard = NULL; zend_long *guard = NULL;
@ -543,12 +543,18 @@ zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_
goto exit; goto exit;
} }
ZVAL_UNDEF(&tmp_object);
/* magic isset */ /* magic isset */
if ((type == BP_VAR_IS) && zobj->ce->__isset) { if ((type == BP_VAR_IS) && zobj->ce->__isset) {
zval tmp_object, tmp_result; zval tmp_result;
guard = zend_get_property_guard(zobj, Z_STR_P(member)); guard = zend_get_property_guard(zobj, Z_STR_P(member));
if (!((*guard) & IN_ISSET)) { 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_COPY(&tmp_object, object);
ZVAL_UNDEF(&tmp_result); ZVAL_UNDEF(&tmp_result);
@ -563,7 +569,6 @@ zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_
goto exit; goto exit;
} }
zval_ptr_dtor(&tmp_object);
zval_ptr_dtor(&tmp_result); zval_ptr_dtor(&tmp_result);
} }
} }
@ -574,10 +579,10 @@ zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_
guard = zend_get_property_guard(zobj, Z_STR_P(member)); guard = zend_get_property_guard(zobj, Z_STR_P(member));
} }
if (!((*guard) & IN_GET)) { if (!((*guard) & IN_GET)) {
zval tmp_object;
/* have getter - try with it! */ /* have getter - try with it! */
if (Z_TYPE(tmp_object) == IS_UNDEF) {
ZVAL_COPY(&tmp_object, object); ZVAL_COPY(&tmp_object, object);
}
*guard |= IN_GET; /* prevent circular getting */ *guard |= IN_GET; /* prevent circular getting */
zend_std_call_getter(&tmp_object, member, rv); zend_std_call_getter(&tmp_object, member, rv);
*guard &= ~IN_GET; *guard &= ~IN_GET;
@ -597,6 +602,7 @@ zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_
zval_ptr_dtor(&tmp_object); zval_ptr_dtor(&tmp_object);
goto exit; goto exit;
} else { } else {
zval_ptr_dtor(&tmp_object);
if (Z_STRVAL_P(member)[0] == '\0') { if (Z_STRVAL_P(member)[0] == '\0') {
if (Z_STRLEN_P(member) == 0) { if (Z_STRLEN_P(member) == 0) {
zend_throw_error(NULL, "Cannot access empty property"); zend_throw_error(NULL, "Cannot access empty property");
@ -610,6 +616,9 @@ zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_
} }
} }
} }
zval_ptr_dtor(&tmp_object);
if ((type != BP_VAR_IS)) { if ((type != BP_VAR_IS)) {
zend_error(E_NOTICE,"Undefined property: %s::$%s", ZSTR_VAL(zobj->ce->name), Z_STRVAL_P(member)); zend_error(E_NOTICE,"Undefined property: %s::$%s", ZSTR_VAL(zobj->ce->name), Z_STRVAL_P(member));
} }
@ -1510,6 +1519,10 @@ found:
zval tmp_object; zval tmp_object;
/* have issetter - try with it! */ /* 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); ZVAL_COPY(&tmp_object, object);
(*guard) |= IN_ISSET; /* prevent circular getting */ (*guard) |= IN_ISSET; /* prevent circular getting */
zend_std_call_issetter(&tmp_object, member, &rv); zend_std_call_issetter(&tmp_object, member, &rv);