Fixed bug #39346 (Unsetting a static variable inside a destructor causes segfault later on)

This commit is contained in:
Dmitry Stogov 2008-01-11 08:42:06 +00:00
parent fa1e1d249b
commit ab5bddd976
4 changed files with 49 additions and 20 deletions

2
NEWS
View File

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

View File

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

26
Zend/tests/bug39346.phpt Normal file
View File

@ -0,0 +1,26 @@
--TEST--
Bug #39346 (Unsetting a static variable inside a destructor causes segfault later on)
--FILE--
<?php
class test
{
protected $_id;
static $instances;
public function __construct($id) {
$this->_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

View File

@ -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) {