diff options
author | Dmitry Stogov <dmitry@php.net> | 2010-10-01 09:49:20 +0000 |
---|---|---|
committer | Dmitry Stogov <dmitry@php.net> | 2010-10-01 09:49:20 +0000 |
commit | f64e4bac49586a416bb397f9f9134477751c39b8 (patch) | |
tree | 131ca67e2af75de92e096f5c4cd40627233f7328 /Zend | |
parent | d252a45e82bcdf624cd4f42e946c57f0e9c8a30c (diff) | |
download | php-git-f64e4bac49586a416bb397f9f9134477751c39b8.tar.gz |
Fixed bug #52879 (Objects unreferenced in __get, __set, __isset or __unset can be freed too early). (mail_ben_schmidt at yahoo dot com dot au, Dmitry)
Diffstat (limited to 'Zend')
-rw-r--r-- | Zend/tests/bug52879.phpt | 16 | ||||
-rw-r--r-- | Zend/zend_object_handlers.c | 49 |
2 files changed, 45 insertions, 20 deletions
diff --git a/Zend/tests/bug52879.phpt b/Zend/tests/bug52879.phpt new file mode 100644 index 0000000000..0193be4b45 --- /dev/null +++ b/Zend/tests/bug52879.phpt @@ -0,0 +1,16 @@ +--TEST-- +Bug #52879 (Objects unreferenced in __get, __set, __isset or __unset can be freed too early) +--FILE-- +<?php +class MyClass { + public $myRef; + public function __set($property,$value) { + $this->myRef = $value; + } +} +$myGlobal=new MyClass($myGlobal); +$myGlobal->myRef=&$myGlobal; +$myGlobal->myNonExistentProperty="ok\n"; +echo $myGlobal; +--EXPECT-- +ok diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 87b68bd2b7..a708f9ad8c 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -419,6 +419,9 @@ zval *zend_std_read_property(zval *object, zval *member, int type, const zend_li !guard->in_get) { /* have getter - try with it! */ Z_ADDREF_P(object); + if (PZVAL_IS_REF(object)) { + SEPARATE_ZVAL(&object); + } guard->in_get = 1; /* prevent circular getting */ rv = zend_std_call_getter(object, member TSRMLS_CC); guard->in_get = 0; @@ -525,30 +528,22 @@ ZEND_API void zend_std_write_property(zval *object, zval *member, zval *value, c } } } else { - int setter_done = 0; zend_guard *guard = NULL; if (zobj->ce->__set && zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS && !guard->in_set) { Z_ADDREF_P(object); + if (PZVAL_IS_REF(object)) { + SEPARATE_ZVAL(&object); + } guard->in_set = 1; /* prevent circular setting */ if (zend_std_call_setter(object, member, value TSRMLS_CC) != SUCCESS) { /* for now, just ignore it - __set should take care of warnings, etc. */ } - setter_done = 1; guard->in_set = 0; zval_ptr_dtor(&object); - } else if (zobj->ce->__set && guard && guard->in_set == 1) { - if (Z_STRVAL_P(member)[0] == '\0') { - if (Z_STRLEN_P(member) == 0) { - zend_error(E_ERROR, "Cannot access empty property"); - } else { - zend_error(E_ERROR, "Cannot access property started with '\\0'"); - } - } - } - if (!setter_done && EXPECTED(property_info != NULL)) { + } else if (EXPECTED(property_info != NULL)) { /* if we assign referenced variable, we should separate it */ Z_ADDREF_P(value); if (PZVAL_IS_REF(value)) { @@ -556,19 +551,27 @@ ZEND_API void zend_std_write_property(zval *object, zval *member, zval *value, c } if (EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) && property_info->offset >= 0) { - if (!zobj->properties) { - zobj->properties_table[property_info->offset] = value; - } else if (zobj->properties_table[property_info->offset]) { - *(zval**)zobj->properties_table[property_info->offset] = value; + if (!zobj->properties) { + zobj->properties_table[property_info->offset] = value; + } else if (zobj->properties_table[property_info->offset]) { + *(zval**)zobj->properties_table[property_info->offset] = value; + } else { + zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &value, sizeof(zval *), (void**)&zobj->properties_table[property_info->offset]); + } } else { - zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &value, sizeof(zval *), (void**)&zobj->properties_table[property_info->offset]); - } - } else { - if (!zobj->properties) { + if (!zobj->properties) { rebuild_object_properties(zobj); } zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &value, sizeof(zval *), NULL); } + } else if (zobj->ce->__set && guard && guard->in_set == 1) { + if (Z_STRVAL_P(member)[0] == '\0') { + if (Z_STRLEN_P(member) == 0) { + zend_error(E_ERROR, "Cannot access empty property"); + } else { + zend_error(E_ERROR, "Cannot access property started with '\\0'"); + } + } } } @@ -770,6 +773,9 @@ static void zend_std_unset_property(zval *object, zval *member, const zend_liter !guard->in_unset) { /* have unseter - try with it! */ Z_ADDREF_P(object); + if (PZVAL_IS_REF(object)) { + SEPARATE_ZVAL(&object); + } guard->in_unset = 1; /* prevent circular unsetting */ zend_std_call_unsetter(object, member TSRMLS_CC); guard->in_unset = 0; @@ -1371,6 +1377,9 @@ static int zend_std_has_property(zval *object, zval *member, int has_set_exists, /* have issetter - try with it! */ Z_ADDREF_P(object); + if (PZVAL_IS_REF(object)) { + SEPARATE_ZVAL(&object); + } guard->in_isset = 1; /* prevent circular getting */ rv = zend_std_call_issetter(object, member TSRMLS_CC); if (rv) { |