Skip to content

Commit bc59289

Browse files
committed
Fixed indirect modification of magic method arguments.
1 parent eaeccc1 commit bc59289

File tree

8 files changed

+131
-7
lines changed

8 files changed

+131
-7
lines changed

Zend/tests/bug75420.1.phpt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Bug #75420.1 (Indirect modification of magic method argument)
3+
--FILE--
4+
<?php
5+
class Test {
6+
public function __isset($x) { $GLOBALS["name"] = 24; return true; }
7+
public function __get($x) { var_dump($x); return 42; }
8+
}
9+
10+
$obj = new Test;
11+
$name = "foo";
12+
var_dump($obj->$name ?? 12);
13+
var_dump($name);
14+
?>
15+
--EXPECT--
16+
string(3) "foo"
17+
int(42)
18+
int(24)

Zend/tests/bug75420.2.phpt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--TEST--
2+
Bug #75420.2 (Indirect modification of magic method argument)
3+
--FILE--
4+
<?php
5+
class Test {
6+
public function __isset($x) { $GLOBALS["name"] = 24; return true; }
7+
public function __get($x) { var_dump($x); return 42; }
8+
}
9+
10+
$obj = new Test;
11+
$name = "foo";
12+
$name = str_repeat($name, 2);
13+
var_dump($obj->$name ?? 12);
14+
var_dump($name);
15+
?>
16+
--EXPECT--
17+
string(6) "foofoo"
18+
int(42)
19+
int(24)
20+

Zend/tests/bug75420.3.phpt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Bug #75420.3 (Indirect modification of magic method argument)
3+
--FILE--
4+
<?php
5+
class Test {
6+
public function __isset($x) { $GLOBALS["name"] = 24; return true; }
7+
public function __get($x) { var_dump($x); return 42; }
8+
}
9+
10+
$obj = new Test;
11+
$name = "foo";
12+
var_dump(empty($obj->$name));
13+
var_dump($name);
14+
?>
15+
--EXPECT--
16+
string(3) "foo"
17+
bool(false)
18+
int(24)

Zend/tests/bug75420.4.phpt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Bug #75420.4 (Indirect modification of magic method argument)
3+
--FILE--
4+
<?php
5+
class Test {
6+
public function __isset($x) { $GLOBALS["name"] = 24; return true; }
7+
public function __get($x) { var_dump($x); return 42; }
8+
}
9+
10+
$obj = new Test;
11+
$name = "foo";
12+
$name = str_repeat($name, 2);
13+
var_dump(empty($obj->$name));
14+
?>
15+
--EXPECT--
16+
string(6) "foofoo"
17+
bool(false)

Zend/tests/bug75420.5.phpt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
Bug #75420.5 (Indirect modification of magic method argument)
3+
--FILE--
4+
<?php
5+
class Test {
6+
public function __isset($x) { $GLOBALS["obj"] = 24; return true; }
7+
public function __get($x) { var_dump($this); return 42; }
8+
}
9+
10+
$obj = new Test;
11+
$name = "foo";
12+
var_dump($obj->$name ?? 12);
13+
var_dump($obj);
14+
?>
15+
--EXPECT--
16+
object(Test)#1 (0) {
17+
}
18+
int(42)
19+
int(24)

Zend/tests/bug75420.6.phpt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
Bug #75420.6 (Indirect modification of magic method argument)
3+
--FILE--
4+
<?php
5+
class Test {
6+
public function __isset($x) { $GLOBALS["obj"] = 24; return true; }
7+
public function __get($x) { var_dump($this); return 42; }
8+
}
9+
10+
$obj = new Test;
11+
$name = "foo";
12+
var_dump(empty($obj->$name));
13+
var_dump($obj);
14+
?>
15+
--EXPECT--
16+
object(Test)#1 (0) {
17+
}
18+
bool(false)
19+
int(24)

Zend/tests/bug75420.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ $name = "foo";
1313
var_dump($obj->$name ?? 12);
1414
?>
1515
--EXPECT--
16-
int(24)
16+
string(3) "foo"
1717
int(42)

Zend/zend_object_handlers.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ static zend_long *zend_get_property_guard(zend_object *zobj, zend_string *member
507507
zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv) /* {{{ */
508508
{
509509
zend_object *zobj;
510-
zval tmp_member;
510+
zval tmp_member, tmp_object;
511511
zval *retval;
512512
uint32_t property_offset;
513513
zend_long *guard = NULL;
@@ -543,12 +543,18 @@ zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_
543543
goto exit;
544544
}
545545

546+
ZVAL_UNDEF(&tmp_object);
547+
546548
/* magic isset */
547549
if ((type == BP_VAR_IS) && zobj->ce->__isset) {
548-
zval tmp_object, tmp_result;
550+
zval tmp_result;
549551
guard = zend_get_property_guard(zobj, Z_STR_P(member));
550552

551553
if (!((*guard) & IN_ISSET)) {
554+
if (Z_TYPE(tmp_member) == IS_UNDEF) {
555+
ZVAL_COPY(&tmp_member, member);
556+
member = &tmp_member;
557+
}
552558
ZVAL_COPY(&tmp_object, object);
553559
ZVAL_UNDEF(&tmp_result);
554560

@@ -563,7 +569,6 @@ zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_
563569
goto exit;
564570
}
565571

566-
zval_ptr_dtor(&tmp_object);
567572
zval_ptr_dtor(&tmp_result);
568573
}
569574
}
@@ -574,10 +579,10 @@ zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_
574579
guard = zend_get_property_guard(zobj, Z_STR_P(member));
575580
}
576581
if (!((*guard) & IN_GET)) {
577-
zval tmp_object;
578-
579582
/* have getter - try with it! */
580-
ZVAL_COPY(&tmp_object, object);
583+
if (Z_TYPE(tmp_object) == IS_UNDEF) {
584+
ZVAL_COPY(&tmp_object, object);
585+
}
581586
*guard |= IN_GET; /* prevent circular getting */
582587
zend_std_call_getter(&tmp_object, member, rv);
583588
*guard &= ~IN_GET;
@@ -597,6 +602,7 @@ zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_
597602
zval_ptr_dtor(&tmp_object);
598603
goto exit;
599604
} else {
605+
zval_ptr_dtor(&tmp_object);
600606
if (Z_STRVAL_P(member)[0] == '\0') {
601607
if (Z_STRLEN_P(member) == 0) {
602608
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_
610616
}
611617
}
612618
}
619+
620+
zval_ptr_dtor(&tmp_object);
621+
613622
if ((type != BP_VAR_IS)) {
614623
zend_error(E_NOTICE,"Undefined property: %s::$%s", ZSTR_VAL(zobj->ce->name), Z_STRVAL_P(member));
615624
}
@@ -1510,6 +1519,10 @@ static int zend_std_has_property(zval *object, zval *member, int has_set_exists,
15101519
zval tmp_object;
15111520

15121521
/* have issetter - try with it! */
1522+
if (Z_TYPE(tmp_member) == IS_UNDEF) {
1523+
ZVAL_COPY(&tmp_member, member);
1524+
member = &tmp_member;
1525+
}
15131526
ZVAL_COPY(&tmp_object, object);
15141527
(*guard) |= IN_ISSET; /* prevent circular getting */
15151528
zend_std_call_issetter(&tmp_object, member, &rv);

0 commit comments

Comments
 (0)