summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2019-08-26 10:23:23 +0200
committerNikita Popov <nikita.ppv@gmail.com>2019-08-26 10:25:30 +0200
commit16d35eb643bf974554e5264021ee10fc969e2053 (patch)
tree31840ba92b19b4d66c3f5257be46a4936f011cb6
parent4b4a656d9e5fac90373521b6624747dd7aa3b9e8 (diff)
downloadphp-git-16d35eb643bf974554e5264021ee10fc969e2053.tar.gz
Fix overflow in memory limit checks
Due to overflows in the memory limit checks, we were missing cases where the allocation size was close to the address space size, and caused an OOM condition rather than a memory limit error.
-rw-r--r--Zend/zend_alloc.c10
-rw-r--r--ext/standard/tests/strings/wordwrap_memory_limit.phpt18
2 files changed, 23 insertions, 5 deletions
diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c
index 3744a83c84..3a43027346 100644
--- a/Zend/zend_alloc.c
+++ b/Zend/zend_alloc.c
@@ -980,7 +980,7 @@ get_chunk:
heap->cached_chunks = chunk->next;
} else {
#if ZEND_MM_LIMIT
- if (UNEXPECTED(heap->real_size + ZEND_MM_CHUNK_SIZE > heap->limit)) {
+ if (UNEXPECTED(ZEND_MM_CHUNK_SIZE > heap->limit - heap->real_size)) {
if (zend_mm_gc(heap)) {
goto get_chunk;
} else if (heap->overflow == 0) {
@@ -1484,8 +1484,8 @@ static void *zend_mm_realloc_heap(zend_mm_heap *heap, void *ptr, size_t size, si
}
} else /* if (new_size > old_size) */ {
#if ZEND_MM_LIMIT
- if (UNEXPECTED(heap->real_size + (new_size - old_size) > heap->limit)) {
- if (zend_mm_gc(heap) && heap->real_size + (new_size - old_size) <= heap->limit) {
+ if (UNEXPECTED(new_size - old_size > heap->limit - heap->real_size)) {
+ if (zend_mm_gc(heap) && new_size - old_size <= heap->limit - heap->real_size) {
/* pass */
} else if (heap->overflow == 0) {
#if ZEND_DEBUG
@@ -1730,8 +1730,8 @@ static void *zend_mm_alloc_huge(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_D
void *ptr;
#if ZEND_MM_LIMIT
- if (UNEXPECTED(heap->real_size + new_size > heap->limit)) {
- if (zend_mm_gc(heap) && heap->real_size + new_size <= heap->limit) {
+ if (UNEXPECTED(new_size > heap->limit - heap->real_size)) {
+ if (zend_mm_gc(heap) && new_size <= heap->limit - heap->real_size) {
/* pass */
} else if (heap->overflow == 0) {
#if ZEND_DEBUG
diff --git a/ext/standard/tests/strings/wordwrap_memory_limit.phpt b/ext/standard/tests/strings/wordwrap_memory_limit.phpt
new file mode 100644
index 0000000000..fb0cc5c3bc
--- /dev/null
+++ b/ext/standard/tests/strings/wordwrap_memory_limit.phpt
@@ -0,0 +1,18 @@
+--TEST--
+No overflow should occur during the memory_limit check for wordwrap()
+--SKIPIF--
+<?php
+if (getenv("USE_ZEND_ALLOC") === "0") die("skip Zend MM disabled");
+?>
+--INI--
+memory_limit=128M
+--FILE--
+<?php
+
+$str = str_repeat('x', 65534);
+$str2 = str_repeat('x', 65535);
+wordwrap($str, 1, $str2);
+
+?>
+--EXPECTF--
+Fatal error: Allowed memory size of 134217728 bytes exhausted%s(tried to allocate %d bytes) in %s on line %d