Fixed bugs #29767 and #31683 (__get and __set methods must not modify property name).

This commit is contained in:
Dmitry Stogov 2005-02-02 07:19:22 +00:00
parent 24a834dfa4
commit fd4fe1c8d3
3 changed files with 133 additions and 8 deletions

97
Zend/tests/bug31683.phpt Normal file
View File

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

View 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"

View 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);