20 Aug 2015, PHP 7.0.0 RC 1
- Core:
+ . Fixed bug #70258 (Segfault if do_resize fails to allocated memory).
+ (Laruence)
+ . Fixed bug #70253 (segfault at _efree () in zend_alloc.c:1389). (Laruence)
. Fixed bug #70240 (Segfault when doing unset($var());). (Laruence)
. Fixed bug #70223 (Incrementing value returned by magic getter). (Laruence)
. Fixed bug #70215 (Segfault when __invoke is static). (Bob)
--- /dev/null
+--TEST--
+Bug #70258 (Segfault if do_resize fails to allocated memory)
+--INI--
+memory_limit=2M
+--SKIPIF--
+<?php
+$zend_mm_enabled = getenv("USE_ZEND_ALLOC");
+if ($zend_mm_enabled === "0") {
+ die("skip Zend MM disabled");
+}
+?>
+--FILE--
+<?php
+class A {
+ public $arr;
+ public function core() {
+ $this->arr["no_pack"] = 1;
+ while (1) {
+ $this->arr[] = 1;
+ }
+ }
+}
+
+$a = new A;
+$a->core();
+?>
+--EXPECTF--
+Fatal error: Allowed memory size of 2097152 bytes exhausted%s(tried to allocate %d bytes) in %s on line %d
zend_hash_rehash(ht);
HANDLE_UNBLOCK_INTERRUPTIONS();
} else if (ht->nTableSize < HT_MAX_SIZE) { /* Let's double the table size */
- void *old_data = HT_GET_DATA_ADDR(ht);
+ void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
+ uint32_t nSize = ht->nTableSize + ht->nTableSize;
Bucket *old_buckets = ht->arData;
HANDLE_BLOCK_INTERRUPTIONS();
- ht->nTableSize += ht->nTableSize;
+ new_data = pemalloc(HT_DATA_SIZE_EX(nSize) + HT_HASH_SIZE_EX(-nSize), ht->u.flags & HASH_FLAG_PERSISTENT);
+ ht->nTableSize = nSize;
ht->nTableMask = -ht->nTableSize;
- HT_SET_DATA_ADDR(ht, pemalloc(HT_SIZE(ht), ht->u.flags & HASH_FLAG_PERSISTENT));
+ HT_SET_DATA_ADDR(ht, new_data);
memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
pefree(old_data, ht->u.flags & HASH_FLAG_PERSISTENT);
zend_hash_rehash(ht);
}
ZEND_API void ZEND_FASTCALL zend_hash_resize(HashTable *ht, uint32_t nSize) {
- void *old_data = HT_GET_DATA_ADDR(ht);
+ nSize = zend_hash_check_size(nSize);
if (ht->u.flags & HASH_FLAG_INITIALIZED) {
+ void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
Bucket *old_buckets = ht->arData;
HANDLE_BLOCK_INTERRUPTIONS();
- ht->nTableSize = zend_hash_check_size(nSize);
+ new_data = pemalloc(HT_DATA_SIZE_EX(nSize) + HT_HASH_SIZE_EX(-nSize), ht->u.flags & HASH_FLAG_PERSISTENT);
+ ht->nTableSize = nSize;
ht->nTableMask = -ht->nTableSize;
- HT_SET_DATA_ADDR(ht, pemalloc(HT_SIZE(ht), ht->u.flags & HASH_FLAG_PERSISTENT));
+ HT_SET_DATA_ADDR(ht, new_data);
memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
pefree(old_data, ht->u.flags & HASH_FLAG_PERSISTENT);
zend_hash_rehash(ht);
HANDLE_UNBLOCK_INTERRUPTIONS();
} else {
- ht->nTableSize = zend_hash_check_size(nSize);
+ ht->nTableSize = nSize;
}
}
#define HT_HASH(ht, idx) \
HT_HASH_EX((ht)->arData, idx)
+#define HT_HASH_SIZE_EX(nTableMask) \
+ (((size_t)(uint32_t)-(int32_t)(nTableMask)) * sizeof(uint32_t))
+#define HT_DATA_SIZE_EX(nTableSize) \
+ ((size_t)(nTableSize) * sizeof(Bucket))
#define HT_HASH_SIZE(ht) \
- (((size_t)(uint32_t)-(int32_t)(ht)->nTableMask) * sizeof(uint32_t))
+ HT_HASH_SIZE_EX((ht)->nTableMask)
#define HT_DATA_SIZE(ht) \
- ((size_t)(ht)->nTableSize * sizeof(Bucket))
+ HT_DATA_SIZE_EX((ht)->nTableSize)
#define HT_SIZE(ht) \
(HT_HASH_SIZE(ht) + HT_DATA_SIZE(ht))
#define HT_USED_SIZE(ht) \