Skip to content

Commit 1b3b5c9

Browse files
pvandommelennikic
authored andcommitted
Fixed bug #81070
When the memory limit is reduced using an `ini_set("memory_limit", ..)` below the currently allocated memory, the out-of-memory check overflowed. Instead of implementing additional checks during allocation, `zend_set_memory_limit()` now validates the new memory limit. When below the current memory usage the ini_set call will fail and throw a warning. This is part of GH-7040.
1 parent 7fd4826 commit 1b3b5c9

File tree

4 files changed

+27
-4
lines changed

4 files changed

+27
-4
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ PHP NEWS
77
. Fixed bug #76359 (open_basedir bypass through adding ".."). (cmb)
88
. Fixed bug #81090 (Typed property performance degradation with .= operator).
99
(Nikita)
10+
. Fixed bug #81070 (Integer underflow in memory limit comparison).
11+
(Peter van Dommelen)
1012

1113
- OpenSSL:
1214
. Fixed bug #76694 (native Windows cert verification uses CN as sever name).

Zend/tests/bug81070.phpt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
--TEST--
2+
Bug #81070 Setting memory limit to below current usage
3+
--FILE--
4+
<?php
5+
$a = str_repeat("0", 5 * 1024 * 1024);
6+
ini_set("memory_limit", "3M");
7+
?>
8+
--EXPECTF--
9+
Warning: Failed to set memory limit to 3145728 bytes (Current memory usage is %d bytes) in %s on line %d

Zend/zend_alloc.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2660,7 +2660,13 @@ ZEND_API char* ZEND_FASTCALL zend_strndup(const char *s, size_t length)
26602660
ZEND_API int zend_set_memory_limit(size_t memory_limit)
26612661
{
26622662
#if ZEND_MM_LIMIT
2663-
AG(mm_heap)->limit = (memory_limit >= ZEND_MM_CHUNK_SIZE) ? memory_limit : ZEND_MM_CHUNK_SIZE;
2663+
if (memory_limit < ZEND_MM_CHUNK_SIZE) {
2664+
memory_limit = ZEND_MM_CHUNK_SIZE;
2665+
}
2666+
if (UNEXPECTED(memory_limit < AG(mm_heap)->real_size)) {
2667+
return FAILURE;
2668+
}
2669+
AG(mm_heap)->limit = memory_limit;
26642670
#endif
26652671
return SUCCESS;
26662672
}

main/main.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -296,12 +296,18 @@ static PHP_INI_MH(OnSetSerializePrecision)
296296
*/
297297
static PHP_INI_MH(OnChangeMemoryLimit)
298298
{
299+
size_t value;
299300
if (new_value) {
300-
PG(memory_limit) = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
301+
value = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
301302
} else {
302-
PG(memory_limit) = Z_L(1)<<30; /* effectively, no limit */
303+
value = Z_L(1)<<30; /* effectively, no limit */
303304
}
304-
return zend_set_memory_limit(PG(memory_limit));
305+
if (zend_set_memory_limit(value) == FAILURE) {
306+
zend_error(E_WARNING, "Failed to set memory limit to %zd bytes (Current memory usage is %zd bytes)", value, zend_memory_usage(true));
307+
return FAILURE;
308+
}
309+
PG(memory_limit) = value;
310+
return SUCCESS;
305311
}
306312
/* }}} */
307313

0 commit comments

Comments
 (0)