diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2019-08-26 10:23:23 +0200 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2019-08-26 10:25:30 +0200 |
commit | 16d35eb643bf974554e5264021ee10fc969e2053 (patch) | |
tree | 31840ba92b19b4d66c3f5257be46a4936f011cb6 | |
parent | 4b4a656d9e5fac90373521b6624747dd7aa3b9e8 (diff) | |
download | php-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.c | 10 | ||||
-rw-r--r-- | ext/standard/tests/strings/wordwrap_memory_limit.phpt | 18 |
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 |