]> granicus.if.org Git - php/commitdiff
Fixed bug #70258 and #70253
authorXinchen Hui <laruence@php.net>
Thu, 13 Aug 2015 04:08:57 +0000 (12:08 +0800)
committerXinchen Hui <laruence@php.net>
Thu, 13 Aug 2015 04:08:57 +0000 (12:08 +0800)
NEWS
Zend/tests/bug70253.phpt [new file with mode: 0644]
Zend/tests/bug70258.phpt [new file with mode: 0644]
Zend/zend_hash.c
Zend/zend_types.h

diff --git a/NEWS b/NEWS
index aaf2417b25a45dee6e2c41657324056ecf3f5720..3741df9dfca5fbfeffc663ef3a0f11589fcf7530 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,9 @@ PHP                                                                        NEWS
 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)
diff --git a/Zend/tests/bug70253.phpt b/Zend/tests/bug70253.phpt
new file mode 100644 (file)
index 0000000..dd760df
--- /dev/null
@@ -0,0 +1,17 @@
+--TEST--
+Bug #70253 (segfault at _efree () in zend_alloc.c:1389)
+--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
+unserialize('a:2:{i:0;O:9:"000000000":10000000');
+?>
+--EXPECTF--
+Fatal error: Allowed memory size of 2097152 bytes exhausted%s(tried to allocate %d bytes) in %s on line %d
diff --git a/Zend/tests/bug70258.phpt b/Zend/tests/bug70258.phpt
new file mode 100644 (file)
index 0000000..5ffd7bf
--- /dev/null
@@ -0,0 +1,28 @@
+--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
index 2347f99432e5443be93420457363ada0f089e1e0..7e06cf0e8cc9144c8fbd32a0da7a86bdb2d68231 100644 (file)
@@ -795,13 +795,15 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht)
                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);
@@ -812,20 +814,22 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *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;
        }
 }
 
index edcbe47f06b00a826bbbb4fcc42c7e077450282b..d4353f7d4deaca9ef615f62a5491ac6b8e1be6fd 100644 (file)
@@ -235,10 +235,14 @@ struct _zend_array {
 #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) \