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.
This commit is contained in:
Nikita Popov 2019-08-26 10:23:23 +02:00
parent 4b4a656d9e
commit 16d35eb643
2 changed files with 23 additions and 5 deletions

View File

@ -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

View File

@ -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