Skip to content

Commit 4e21924

Browse files
frederikpytiluuu1994
authored andcommitted
Fix GH-17951: Addition of max_memory_limit INI
Closes GH-18011
1 parent 9aa8e88 commit 4e21924

15 files changed

+209
-1
lines changed

UPGRADING

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,11 @@ PHP 8.5 UPGRADE NOTES
629629
. Added fatal_error_backtraces to control whether fatal errors should include
630630
a backtrace.
631631
RFC: https://wiki.php.net/rfc/error_backtraces_v2
632+
. Added startup-only max_memory_limit INI setting to control the maximum
633+
memory_limit that may be configured at startup or runtime. Exceeding this
634+
value emits a warning, unless set to -1, and sets memory_limit to the
635+
current max_memory_limit instead.
636+
ML discussion: https://externals.io/message/127108
632637

633638
- Opcache:
634639
. Added opcache.file_cache_read_only to support a read-only

main/main.c

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,33 @@ static PHP_INI_MH(OnChangeMemoryLimit)
332332
} else {
333333
value = Z_L(1)<<30; /* effectively, no limit */
334334
}
335+
336+
/* If max_memory_limit is not set to unlimited, verify change */
337+
if (PG(max_memory_limit) != -1) {
338+
if (value == -1) {
339+
zend_error(
340+
E_WARNING,
341+
"Failed to set memory_limit to unlimited. memory_limit (currently: " ZEND_LONG_FMT " bytes) cannot be set to unlimited if max_memory_limit (" ZEND_LONG_FMT " bytes) is not unlimited",
342+
PG(memory_limit),
343+
PG(max_memory_limit)
344+
);
345+
346+
return FAILURE;
347+
}
348+
349+
if (value > PG(max_memory_limit)) {
350+
zend_error(
351+
E_WARNING,
352+
"Failed to set memory_limit to %zd bytes. memory_limit (currently: " ZEND_LONG_FMT " bytes) cannot exceed max_memory_limit (" ZEND_LONG_FMT " bytes)",
353+
value,
354+
PG(memory_limit),
355+
PG(max_memory_limit)
356+
);
357+
358+
return FAILURE;
359+
}
360+
}
361+
335362
if (zend_set_memory_limit(value) == FAILURE) {
336363
/* When the memory limit is reset to the original level during deactivation, we may be
337364
* using more memory than the original limit while shutdown is still in progress.
@@ -347,6 +374,26 @@ static PHP_INI_MH(OnChangeMemoryLimit)
347374
}
348375
/* }}} */
349376

377+
static PHP_INI_MH(OnChangeMaxMemoryLimit)
378+
{
379+
size_t value;
380+
if (new_value) {
381+
value = zend_ini_parse_uquantity_warn(new_value, entry->name);
382+
} else {
383+
value = Z_L(1) << 30; /* effectively, no limit */
384+
}
385+
386+
if (zend_set_memory_limit(value) == FAILURE) {
387+
zend_error(E_ERROR, "Failed to set memory limit to %zd bytes (Current memory usage is %zd bytes)", value, zend_memory_usage(true));
388+
return FAILURE;
389+
}
390+
391+
PG(memory_limit) = value;
392+
PG(max_memory_limit) = value;
393+
394+
return SUCCESS;
395+
}
396+
350397
/* {{{ PHP_INI_MH */
351398
static PHP_INI_MH(OnSetLogFilter)
352399
{
@@ -810,7 +857,10 @@ PHP_INI_BEGIN()
810857
STD_PHP_INI_BOOLEAN("mail.mixed_lf_and_crlf", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, mail_mixed_lf_and_crlf, php_core_globals, core_globals)
811858
STD_PHP_INI_ENTRY("mail.log", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateMailLog, mail_log, php_core_globals, core_globals)
812859
PHP_INI_ENTRY("browscap", NULL, PHP_INI_SYSTEM, OnChangeBrowscap)
813-
PHP_INI_ENTRY("memory_limit", "128M", PHP_INI_ALL, OnChangeMemoryLimit)
860+
861+
PHP_INI_ENTRY("max_memory_limit", "-1", PHP_INI_SYSTEM, OnChangeMaxMemoryLimit)
862+
PHP_INI_ENTRY("memory_limit", "128M", PHP_INI_ALL, OnChangeMemoryLimit)
863+
814864
PHP_INI_ENTRY("precision", "14", PHP_INI_ALL, OnSetPrecision)
815865
PHP_INI_ENTRY("sendmail_from", NULL, PHP_INI_ALL, NULL)
816866
PHP_INI_ENTRY("sendmail_path", DEFAULT_SENDMAIL_PATH, PHP_INI_SYSTEM, NULL)

main/php_globals.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ struct _php_core_globals {
7272
zend_long serialize_precision;
7373

7474
zend_long memory_limit;
75+
zend_long max_memory_limit;
7576
zend_long max_input_time;
7677

7778
char *error_log;

php.ini-development

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ max_input_time = 60
436436
; Maximum amount of memory a script may consume
437437
; https://php.net/memory-limit
438438
memory_limit = 128M
439+
max_memory_limit = -1
439440

440441
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
441442
; Error handling and logging ;

php.ini-production

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ max_input_time = 60
438438
; Maximum amount of memory a script may consume
439439
; https://php.net/memory-limit
440440
memory_limit = 128M
441+
max_memory_limit = -1
441442

442443
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
443444
; Error handling and logging ;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
--TEST--
2+
GH-17951 INI Parse 1
3+
--CREDITS--
4+
Frederik Milling Pytlick ([email protected])
5+
--INI--
6+
memory_limit=128M
7+
max_memory_limit=-1
8+
--FILE--
9+
<?php
10+
echo ini_get('max_memory_limit') . PHP_EOL;
11+
echo ini_get('memory_limit') . PHP_EOL;
12+
?>
13+
--EXPECT--
14+
-1
15+
128M
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
--TEST--
2+
GH-17951 INI Parse 2
3+
--CREDITS--
4+
Frederik Milling Pytlick ([email protected])
5+
--INI--
6+
memory_limit=-1
7+
max_memory_limit=-1
8+
--FILE--
9+
<?php
10+
echo ini_get('max_memory_limit') . PHP_EOL;
11+
echo ini_get('memory_limit') . PHP_EOL;
12+
?>
13+
--EXPECT--
14+
-1
15+
-1
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
--TEST--
2+
GH-17951 INI Parse 3
3+
--CREDITS--
4+
Frederik Milling Pytlick ([email protected])
5+
--INI--
6+
memory_limit=128M
7+
max_memory_limit=256M
8+
--FILE--
9+
<?php
10+
echo ini_get('max_memory_limit') . PHP_EOL;
11+
echo ini_get('memory_limit') . PHP_EOL;
12+
?>
13+
--EXPECT--
14+
256M
15+
128M
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
--TEST--
2+
GH-17951 INI Parse 4
3+
--CREDITS--
4+
Frederik Milling Pytlick ([email protected])
5+
--INI--
6+
memory_limit=-1
7+
max_memory_limit=128M
8+
--FILE--
9+
<?php
10+
echo ini_get('max_memory_limit') . PHP_EOL;
11+
echo ini_get('memory_limit') . PHP_EOL;
12+
--EXPECTF--
13+
Warning: Failed to set memory_limit to unlimited. memory_limit (currently: %d bytes) cannot be set to unlimited if max_memory_limit (%d bytes) is not unlimited in %s
14+
128M
15+
128M
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
--TEST--
2+
GH-17951 INI Parse 5
3+
--CREDITS--
4+
Frederik Milling Pytlick ([email protected])
5+
--INI--
6+
memory_limit=256M
7+
max_memory_limit=128M
8+
--FILE--
9+
<?php
10+
echo ini_get('max_memory_limit') . PHP_EOL;
11+
echo ini_get('memory_limit') . PHP_EOL;
12+
--EXPECTF--
13+
Warning: Failed to set memory_limit to %d bytes. memory_limit (currently: %d bytes) cannot exceed max_memory_limit (%d bytes) in %s
14+
128M
15+
128M

0 commit comments

Comments
 (0)