Skip to content

Fix GH-17951: Addition of max_memory_limit INI #18011

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Next Next commit
Fix GH-17951: Addition of max_memory_limit INI
  • Loading branch information
frederikpyt committed Mar 10, 2025
commit 9341c6e5b19c7f6e3a4f32b6de5981d31af77852
79 changes: 63 additions & 16 deletions main/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -317,23 +317,67 @@ static PHP_INI_MH(OnSetSerializePrecision)
static PHP_INI_MH(OnChangeMemoryLimit)
{
size_t value;
if (new_value) {
value = zend_ini_parse_uquantity_warn(new_value, entry->name);
} else {
value = Z_L(1)<<30; /* effectively, no limit */
}
if (zend_set_memory_limit(value) == FAILURE) {
/* When the memory limit is reset to the original level during deactivation, we may be
* using more memory than the original limit while shutdown is still in progress.
* Ignore a failure for now, and set the memory limit when the memory manager has been
* shut down and the minimal amount of memory is used. */
if (stage != ZEND_INI_STAGE_DEACTIVATE) {
zend_error(E_WARNING, "Failed to set memory limit to %zd bytes (Current memory usage is %zd bytes)", value, zend_memory_usage(true));
return FAILURE;

if (new_value) {
value = zend_ini_parse_uquantity_warn(new_value, entry->name);
} else {
value = Z_L(1) << 30; /* effectively, no limit */
}

/* If max_memory_limit is not set to unlimited, memory_limit cannot be set to unlimited. */
if (value == -1 && PG(max_memory_limit) != -1) {
if (PG(memory_limit) == 0) {
/* memory_limit exceeds max_memory_limit at INI parsing. */
zend_error(E_ERROR, "memory_limit cannot be set to unlimited when max_memory_limit (%zd bytes) is not unlimited", PG(max_memory_limit));
zend_bailout();
exit(1);
} else {
/* new memory_limit exceeds max_memory_limit at runtime. */
zend_error(E_WARNING, "Failed to set memory_limit to unlimited. memory_limit (currently: %zd bytes) cannot be set to unlimited if max_memory_limit (%zd bytes) is not unlimited", PG(memory_limit), PG(max_memory_limit));
}

return FAILURE;
}
PG(memory_limit) = value;
return SUCCESS;

/* Enforce max_memory_limit if not unlimited */
if (PG(max_memory_limit) != -1 && value > PG(max_memory_limit)) {
if (PG(memory_limit) == 0) {
/* memory_limit exceeds max_memory_limit at INI parsing. */
zend_error(E_ERROR, "memory_limit (%zd bytes) exceeds max_memory_limit (%zd bytes)", value, PG(max_memory_limit));
zend_bailout();
exit(1);
} else {
/* new memory_limit exceeds max_memory_limit at runtime. */
zend_error(E_WARNING, "Failed to set memory_limit to %zd bytes. memory_limit (currently: %zd bytes) cannot exceed max_memory_limit (%zd bytes)", value, PG(memory_limit), PG(max_memory_limit));
}

return FAILURE;
}

if (zend_set_memory_limit(value) == FAILURE) {
if (stage != ZEND_INI_STAGE_DEACTIVATE) {
zend_error(E_WARNING, "Failed to set memory limit to %zd bytes (Current memory usage is %zd bytes)", value, zend_memory_usage(true));
return FAILURE;
}
}

PG(memory_limit) = value;
return SUCCESS;
}
/* }}} */

/* {{{ PHP_INI_MH */
static PHP_INI_MH(OnChangeMaxMemoryLimit)
{
size_t value;
if (new_value) {
value = zend_ini_parse_uquantity_warn(new_value, entry->name);
} else {
value = Z_L(1) << 30; /* effectively, no limit */
}

PG(max_memory_limit) = value;
return SUCCESS;
}
/* }}} */

Expand Down Expand Up @@ -800,7 +844,10 @@ PHP_INI_BEGIN()
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)
STD_PHP_INI_ENTRY("mail.log", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateMailLog, mail_log, php_core_globals, core_globals)
PHP_INI_ENTRY("browscap", NULL, PHP_INI_SYSTEM, OnChangeBrowscap)
PHP_INI_ENTRY("memory_limit", "128M", PHP_INI_ALL, OnChangeMemoryLimit)

PHP_INI_ENTRY("max_memory_limit", "-1", PHP_INI_SYSTEM, OnChangeMaxMemoryLimit)
PHP_INI_ENTRY("memory_limit", "128M", PHP_INI_ALL, OnChangeMemoryLimit)

PHP_INI_ENTRY("precision", "14", PHP_INI_ALL, OnSetPrecision)
PHP_INI_ENTRY("sendmail_from", NULL, PHP_INI_ALL, NULL)
PHP_INI_ENTRY("sendmail_path", DEFAULT_SENDMAIL_PATH, PHP_INI_SYSTEM, NULL)
Expand Down
1 change: 1 addition & 0 deletions main/php_globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ struct _php_core_globals {
zend_long serialize_precision;

zend_long memory_limit;
zend_long max_memory_limit;
zend_long max_input_time;

char *error_log;
Expand Down
1 change: 1 addition & 0 deletions php.ini-development
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ max_input_time = 60
; Maximum amount of memory a script may consume
; https://php.net/memory-limit
memory_limit = 128M
max_memory_limit = -1

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Error handling and logging ;
Expand Down
1 change: 1 addition & 0 deletions php.ini-production
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,7 @@ max_input_time = 60
; Maximum amount of memory a script may consume
; https://php.net/memory-limit
memory_limit = 128M
max_memory_limit = -1

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Error handling and logging ;
Expand Down
13 changes: 13 additions & 0 deletions tests/basic/gh17951_ini_parse_1.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--TEST--
GH-17951 INI Parse 1
--CREDITS--
Frederik Milling Pytlick
frederikpyt@protonmail.com
--INI--
memory_limit=128M
max_memory_limit=-1
--FILE--
<?php
echo "OK";
--EXPECT--
OK
13 changes: 13 additions & 0 deletions tests/basic/gh17951_ini_parse_2.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--TEST--
GH-17951 INI Parse 2
--CREDITS--
Frederik Milling Pytlick
frederikpyt@protonmail.com
--INI--
memory_limit=-1
max_memory_limit=-1
--FILE--
<?php
echo "OK";
--EXPECT--
OK
13 changes: 13 additions & 0 deletions tests/basic/gh17951_ini_parse_3.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--TEST--
GH-17951 INI Parse 3
--CREDITS--
Frederik Milling Pytlick
frederikpyt@protonmail.com
--INI--
memory_limit=128M
max_memory_limit=256M
--FILE--
<?php
echo "OK";
--EXPECT--
OK
12 changes: 12 additions & 0 deletions tests/basic/gh17951_ini_parse_4.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
--TEST--
GH-17951 INI Parse 4
--CREDITS--
Frederik Milling Pytlick
frederikpyt@protonmail.com
--INI--
memory_limit=-1
max_memory_limit=128M
--FILE--
<?php
--EXPECTF--
Fatal error: memory_limit cannot be set to unlimited when max_memory_limit (%d bytes) is not unlimited in %s
12 changes: 12 additions & 0 deletions tests/basic/gh17951_ini_parse_5.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
--TEST--
GH-17951 INI Parse 5
--CREDITS--
Frederik Milling Pytlick
frederikpyt@protonmail.com
--INI--
memory_limit=256M
max_memory_limit=128M
--FILE--
<?php
--EXPECTF--
Fatal error: memory_limit (%d bytes) exceeds max_memory_limit (%d bytes) in %s
14 changes: 14 additions & 0 deletions tests/basic/gh17951_runtime_change_1.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
GH-17951 Runtime Change 1
--CREDITS--
Frederik Milling Pytlick
frederikpyt@protonmail.com
--INI--
memory_limit=128M
max_memory_limit=512M
--FILE--
<?php
ini_set('memory_limit', '256M');
echo ini_get('memory_limit') . PHP_EOL . PHP_EOL;
--EXPECT--
256M
14 changes: 14 additions & 0 deletions tests/basic/gh17951_runtime_change_2.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
GH-17951 Runtime Change 2
--CREDITS--
Frederik Milling Pytlick
frederikpyt@protonmail.com
--INI--
memory_limit=128M
max_memory_limit=512M
--FILE--
<?php
ini_set('memory_limit', '512M');
echo ini_get('memory_limit') . PHP_EOL . PHP_EOL;
--EXPECT--
512M
15 changes: 15 additions & 0 deletions tests/basic/gh17951_runtime_change_3.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
GH-17951 Runtime Change 3
--CREDITS--
Frederik Milling Pytlick
frederikpyt@protonmail.com
--INI--
memory_limit=128M
max_memory_limit=512M
--FILE--
<?php
ini_set('memory_limit', '1024M');
echo ini_get('memory_limit');
--EXPECTF--
Warning: Failed to set memory_limit to %d bytes. memory_limit (currently: %d bytes) cannot exceed max_memory_limit (%d bytes) in %s
128M
15 changes: 15 additions & 0 deletions tests/basic/gh17951_runtime_change_4.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
GH-17951 Runtime Change 4
--CREDITS--
Frederik Milling Pytlick
frederikpyt@protonmail.com
--INI--
memory_limit=128M
max_memory_limit=512M
--FILE--
<?php
ini_set('memory_limit', '-1');
echo ini_get('memory_limit');
--EXPECTF--
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
128M
19 changes: 19 additions & 0 deletions tests/basic/gh17951_runtime_change_5.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
GH-17951 Runtime Change 5
--CREDITS--
Frederik Milling Pytlick
frederikpyt@protonmail.com
--INI--
memory_limit=128M
max_memory_limit=512M
--FILE--
<?php
var_dump(ini_set('max_memory_limit', '128M'));
var_dump(ini_set('max_memory_limit', '256M'));
var_dump(ini_set('max_memory_limit', '512M'));
var_dump(ini_set('max_memory_limit', '-1'));
--EXPECT--
bool(false)
bool(false)
bool(false)
bool(false)
Loading