mirror of
https://github.com/php/php-src.git
synced 2024-11-24 10:24:11 +08:00
Fix bug #65051: count() off by one inside unset()
nNumOfElements was incremented after the pDestructor code, so any code in the dtor would get a wrong number of elements. Right now the bucket deletion code is replicated in four places, it should probably be moved off into one function (or rather, zend_hash_apply_deleter should be used everywhere). The codes are subtly different though in that the HANDLE_UNBLOCK_INTERRUPTIONS() happens in different places. In particular it seems odd that in some cases interruptions stay blocked during the destructor call.
This commit is contained in:
parent
d587efb7ee
commit
86434be946
1
NEWS
1
NEWS
@ -10,6 +10,7 @@ PHP NEWS
|
||||
. Fixed bug #64934 (Apache2 TS crash with get_browser()). (Anatol)
|
||||
. Fixed bug #64166 (quoted-printable-encode stream filter incorrectly
|
||||
discarding whitespace). (Michael M Slusarz)
|
||||
. Fixed bug #65051 (count() off by one inside unset()). (Nikita)
|
||||
|
||||
- FPM:
|
||||
. Implemented FR #64764 (add support for FPM init.d script). (Lior Kaplan)
|
||||
|
23
Zend/tests/bug65051.phpt
Normal file
23
Zend/tests/bug65051.phpt
Normal file
@ -0,0 +1,23 @@
|
||||
--TEST--
|
||||
Bug #65051: count() off by one inside unset()
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Foo {
|
||||
public $array;
|
||||
|
||||
public function __destruct() {
|
||||
var_dump(count($this->array[0]));
|
||||
var_dump($this->array[0]);
|
||||
}
|
||||
}
|
||||
|
||||
$array = [[new Foo]];
|
||||
$array[0][0]->array =& $array;
|
||||
unset($array[0][0]);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
int(0)
|
||||
array(0) {
|
||||
}
|
@ -527,6 +527,7 @@ ZEND_API int zend_hash_del_key_or_index(HashTable *ht, const char *arKey, uint n
|
||||
if (ht->pInternalPointer == p) {
|
||||
ht->pInternalPointer = p->pListNext;
|
||||
}
|
||||
ht->nNumOfElements--;
|
||||
if (ht->pDestructor) {
|
||||
ht->pDestructor(p->pData);
|
||||
}
|
||||
@ -535,7 +536,6 @@ ZEND_API int zend_hash_del_key_or_index(HashTable *ht, const char *arKey, uint n
|
||||
}
|
||||
pefree(p, ht->persistent);
|
||||
HANDLE_UNBLOCK_INTERRUPTIONS();
|
||||
ht->nNumOfElements--;
|
||||
return SUCCESS;
|
||||
}
|
||||
p = p->pNext;
|
||||
@ -1320,6 +1320,7 @@ ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, const
|
||||
if (ht->pInternalPointer == p) {
|
||||
ht->pInternalPointer = p->pListNext;
|
||||
}
|
||||
ht->nNumOfElements--;
|
||||
if (ht->pDestructor) {
|
||||
ht->pDestructor(p->pData);
|
||||
}
|
||||
@ -1327,7 +1328,6 @@ ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, const
|
||||
pefree(p->pData, ht->persistent);
|
||||
}
|
||||
pefree(p, ht->persistent);
|
||||
ht->nNumOfElements--;
|
||||
HANDLE_UNBLOCK_INTERRUPTIONS();
|
||||
return FAILURE;
|
||||
}
|
||||
@ -1355,6 +1355,7 @@ ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, const
|
||||
if (ht->pInternalPointer == q) {
|
||||
ht->pInternalPointer = q->pListNext;
|
||||
}
|
||||
ht->nNumOfElements--;
|
||||
if (ht->pDestructor) {
|
||||
ht->pDestructor(q->pData);
|
||||
}
|
||||
@ -1362,7 +1363,6 @@ ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, const
|
||||
pefree(q->pData, ht->persistent);
|
||||
}
|
||||
pefree(q, ht->persistent);
|
||||
ht->nNumOfElements--;
|
||||
}
|
||||
|
||||
if (p->pNext) {
|
||||
|
Loading…
Reference in New Issue
Block a user