From 8a7c2ff618dad816d5557cb215e0395191bebf05 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Wed, 2 Feb 2005 07:19:02 +0000 Subject: [PATCH] Fixed bugs #29767 and #31683 (__get and __set methods must not modify property name). --- NEWS | 3 ++ Zend/tests/bug31683.phpt | 97 +++++++++++++++++++++++++++++++++++++ Zend/zend.h | 14 ++++++ Zend/zend_object_handlers.c | 26 +++++++--- 4 files changed, 133 insertions(+), 7 deletions(-) create mode 100644 Zend/tests/bug31683.phpt diff --git a/NEWS b/NEWS index 70b1171167..1196f9092a 100644 --- a/NEWS +++ b/NEWS @@ -23,6 +23,8 @@ PHP NEWS - Fixed bug #31705 (parse_url() does not recognize http://foo.com#bar). (Ilia) - Fixed bug #31684 (dio_tcsetattr(): misconfigured termios settings). (elod at itfais dot com) +- Fixed bug #31683 (changes to $name in __get($name) override future + parameters). (Dmitry) - Fixed bug #31699 (unserialize() float problem on non-English locales). (Ilia) - Fixed bug #31651 (ReflectionClass::getDefaultProperties segfaults with arrays). (Marcus) @@ -72,6 +74,7 @@ PHP NEWS in segfault). (pdan-php at esync dot org, Tony) - Fixed bug #30120 (imagettftext() and imagettfbbox() accept too many parameters). (Jani) +- Fixed bug #29767 (Weird behaviour of __set($name, $value)). (Dmitry) - Fixed bug #29733 (printf() handles repeated placeholders wrong). (bugs dot php dot net at bluetwanger dot de, Ilia) - Fixed bug #29136 (make test - libtool failure on MacOSX). (Jani) diff --git a/Zend/tests/bug31683.phpt b/Zend/tests/bug31683.phpt new file mode 100644 index 0000000000..4e0159d6c2 --- /dev/null +++ b/Zend/tests/bug31683.phpt @@ -0,0 +1,97 @@ +--TEST-- +Bug #31683 (changes to $name in __get($name) override future parameters) +--SKIPIF-- + +--FILE-- +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" +--- diff --git a/Zend/zend.h b/Zend/zend.h index 7470c936f8..f8fc805762 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -603,6 +603,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 diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 10f9dfef01..e9353d9315 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -72,6 +72,7 @@ static zval *zend_std_call_getter(zval *object, zval *member TSRMLS_DC) INIT_PZVAL(&__get_name); ZVAL_STRINGL(&__get_name, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)-1, 0); + SEPARATE_ARG_IF_REF(member); call_args[0] = &member; /* go call the __get handler */ @@ -87,11 +88,13 @@ static zval *zend_std_call_getter(zval *object, zval *member TSRMLS_DC) retval returns the value that is received */ - if (call_result == FAILURE) { zend_error(E_ERROR, "Could not call __get handler for class %s", Z_OBJCE_P(object)->name); return NULL; } + + zval_ptr_dtor(&member); + if (retval) { retval->refcount--; } @@ -116,6 +119,7 @@ static int zend_std_call_setter(zval *object, zval *member, zval *value TSRMLS_D INIT_PZVAL(&__set_name); ZVAL_STRINGL(&__set_name, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)-1, 0); + SEPARATE_ARG_IF_REF(member); call_args[0] = &member; value->refcount++; call_args[1] = &value; @@ -139,6 +143,7 @@ static int zend_std_call_setter(zval *object, zval *member, zval *value TSRMLS_D return FAILURE; } + zval_ptr_dtor(&member); zval_ptr_dtor(&value); if (retval && zend_is_true(retval)) { @@ -383,12 +388,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); @@ -410,14 +417,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); } @@ -431,7 +439,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; @@ -516,7 +526,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); -- 2.40.0