]> granicus.if.org Git - php/commitdiff
Fix #78620: Out of memory error
authorChristoph M. Becker <cmbecker69@gmx.de>
Thu, 3 Oct 2019 17:23:05 +0000 (19:23 +0200)
committerChristoph M. Becker <cmbecker69@gmx.de>
Fri, 4 Oct 2019 07:08:01 +0000 (09:08 +0200)
The integer addition in `ZEND_MM_ALIGNED_SIZE_EX` can overflow, what we
have to catch early.

NEWS
Zend/zend_alloc.c
ext/standard/tests/strings/wordwrap_memory_limit.phpt
ext/standard/tests/strings/wordwrap_memory_limit_win32.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 26abd33994ad939ef21e075337bef11b172e4926..a04f3bf3f8cc3466d32529972af1dfc71d342300 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,7 @@ PHP                                                                        NEWS
 - Core:
   . Fixed bug #78535 (auto_detect_line_endings value not parsed as bool).
     (bugreportuser)
+  . Fixed bug #78620 (Out of memory error). (cmb, Nikita)
 
 - Exif:
   . Fixed bug #78442 ('Illegal component' on exif_read_data since PHP7)
index 3a43027346dba32aa846537622b23192daeb09ff..f4a6179516e4a611932bfce6c232b0ca3b138bc9 100644 (file)
@@ -1723,12 +1723,17 @@ static void *zend_mm_alloc_huge(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_D
         * We allocate them with 2MB size granularity, to avoid many
         * reallocations when they are extended by small pieces
         */
-       size_t new_size = ZEND_MM_ALIGNED_SIZE_EX(size, MAX(REAL_PAGE_SIZE, ZEND_MM_CHUNK_SIZE));
+       size_t alignment = MAX(REAL_PAGE_SIZE, ZEND_MM_CHUNK_SIZE);
 #else
-       size_t new_size = ZEND_MM_ALIGNED_SIZE_EX(size, REAL_PAGE_SIZE);
+       size_t alignment = REAL_PAGE_SIZE;
 #endif
+       size_t new_size = ZEND_MM_ALIGNED_SIZE_EX(size, alignment);
        void *ptr;
 
+       if (UNEXPECTED(new_size < size)) {
+               zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu + %zu)", size, alignment);
+       }
+
 #if ZEND_MM_LIMIT
        if (UNEXPECTED(new_size > heap->limit - heap->real_size)) {
                if (zend_mm_gc(heap) && new_size <= heap->limit - heap->real_size) {
index fb0cc5c3bc6842b7a8a443a31119a5562e414f3d..21340153faea1c9f14d96cdba2afc57a43bf3192 100644 (file)
@@ -2,6 +2,7 @@
 No overflow should occur during the memory_limit check for wordwrap()
 --SKIPIF--
 <?php
+if (substr(PHP_OS, 0, 3) == 'WIN' && PHP_INT_SIZE == 4) die("skip this test is not for 32bit Windows platforms");
 if (getenv("USE_ZEND_ALLOC") === "0") die("skip Zend MM disabled");
 ?>
 --INI--
diff --git a/ext/standard/tests/strings/wordwrap_memory_limit_win32.phpt b/ext/standard/tests/strings/wordwrap_memory_limit_win32.phpt
new file mode 100644 (file)
index 0000000..e0e76b5
--- /dev/null
@@ -0,0 +1,19 @@
+--TEST--
+No overflow should occur during the memory_limit check for wordwrap()
+--SKIPIF--
+<?php
+if (substr(PHP_OS, 0, 3) != 'WIN' || PHP_INT_SIZE != 4) die("skip this test is for 32bit Windows platforms only");
+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: Possible integer overflow in memory allocation (4294901777 + %d) in %s on line %d