From ab5bddd976fb511a6c78723d0f12a09059213c74 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Fri, 11 Jan 2008 08:42:06 +0000 Subject: [PATCH] Fixed bug #39346 (Unsetting a static variable inside a destructor causes segfault later on) --- NEWS | 2 ++ Zend/tests/bug32799.phpt | 16 ++++++++-------- Zend/tests/bug39346.phpt | 26 ++++++++++++++++++++++++++ Zend/zend_execute.c | 25 +++++++++++++------------ 4 files changed, 49 insertions(+), 20 deletions(-) create mode 100644 Zend/tests/bug39346.phpt diff --git a/NEWS b/NEWS index 96031f995b..e6e4e5661c 100644 --- a/NEWS +++ b/NEWS @@ -91,6 +91,8 @@ PHP NEWS - Fixed bug #39700 (NUMERIC error when result precision are 7,8 or 12-14 ). (Lars W) - Fixed bug #39397 (invalid statement handle in Unknown on line 0). (Lars W) +- Fixed bug #39346 (Unsetting a static variable inside a destructor causes + segfault later on). (Dmitry) - Fixed bug #39056 (Interbase NUMERIC data type error). (Lars W) - Fixed bug #38468 (Unexpected creation of cycle). (Dmitry) - Fixed bug #37911 (preg_replace_callback() ignores named groups). (Nuno) diff --git a/Zend/tests/bug32799.phpt b/Zend/tests/bug32799.phpt index 7b09a50274..c76daeddef 100755 --- a/Zend/tests/bug32799.phpt +++ b/Zend/tests/bug32799.phpt @@ -5,17 +5,17 @@ Bug #32799 (crash: calling the corresponding global var during the destruct) class test{ public $c=1; function __destruct (){ - $GLOBALS['p']->c++; // no warning - print $GLOBALS['p']->c."\n"; // segfault - var_dump($GLOBALS['p']); + if (!isset($GLOBALS['p'])) { + echo "NULL\n"; + } else { + $GLOBALS['p']->c++; // no warning + print $GLOBALS['p']->c."\n"; // segfault + var_dump($GLOBALS['p']); + } } } $p=new test; $p=null; //destroy the object by a new assignment (segfault) ?> --EXPECT-- -2 -object(test)#1 (1) { - ["c"]=> - int(2) -} +NULL diff --git a/Zend/tests/bug39346.phpt b/Zend/tests/bug39346.phpt new file mode 100644 index 0000000000..4a614c9e9a --- /dev/null +++ b/Zend/tests/bug39346.phpt @@ -0,0 +1,26 @@ +--TEST-- +Bug #39346 (Unsetting a static variable inside a destructor causes segfault later on) +--FILE-- +_id = $id; + self::$instances[$this->_id] = $this; + } + + function __destruct() { + unset(self::$instances[$this->_id]); + } +} +$test = new test(2); +$test = new test(1); +$test = new test(2); +$test = new test(3); +echo "ok\n"; +?> +--EXPECT-- +ok diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 865a4003f3..1f417fab0e 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -691,6 +691,7 @@ static inline void zend_assign_to_string_offset(temp_variable *T, zval *value, i static inline zval* zend_assign_to_variable(zval **variable_ptr_ptr, zval *value, int is_tmp_var TSRMLS_DC) { zval *variable_ptr = *variable_ptr_ptr; + zval garbage; if (variable_ptr == EG(error_zval_ptr)) { if (is_tmp_var) { @@ -716,7 +717,6 @@ static inline zval* zend_assign_to_variable(zval **variable_ptr_ptr, zval *value } else if (PZVAL_IS_REF(variable_ptr)) { if (variable_ptr != value) { zend_uint refcount = Z_REFCOUNT_P(variable_ptr); - zval garbage; if (!is_tmp_var) { Z_ADDREF_P(value); @@ -756,7 +756,6 @@ static inline zval* zend_assign_to_variable(zval **variable_ptr_ptr, zval *value } else if (PZVAL_IS_REF(variable_ptr)) { if (variable_ptr!=value) { zend_uint refcount = Z_REFCOUNT_P(variable_ptr); - zval garbage; if (!is_tmp_var) { Z_ADDREF_P(value); @@ -778,23 +777,25 @@ static inline zval* zend_assign_to_variable(zval **variable_ptr_ptr, zval *value if (variable_ptr==value) { Z_ADDREF_P(variable_ptr); } else if (PZVAL_IS_REF(value)) { - zval tmp; - - tmp = *value; - zval_copy_ctor(&tmp); - Z_SET_REFCOUNT(tmp, 1); - zendi_zval_dtor(*variable_ptr); - *variable_ptr = tmp; + garbage = *variable_ptr; + *variable_ptr = *value; + INIT_PZVAL(variable_ptr); + zval_copy_ctor(variable_ptr); + zendi_zval_dtor(garbage); + return variable_ptr; } else { Z_ADDREF_P(value); + *variable_ptr_ptr = value; zendi_zval_dtor(*variable_ptr); safe_free_zval_ptr(variable_ptr); - *variable_ptr_ptr = value; + return value; } } else { - zendi_zval_dtor(*variable_ptr); - Z_SET_REFCOUNT_P(value, 1); + garbage = *variable_ptr; *variable_ptr = *value; + INIT_PZVAL(variable_ptr); + zendi_zval_dtor(garbage); + return variable_ptr; } } else { /* we need to split */ if (!is_tmp_var) { -- 2.40.0