When the memory limit is restored during shutdown, we may still
be using a lot of memory. Ignore the failure at that point and
set it again after the MM is shut down, at which point memory
usage should be at its lowest point.
This commit is contained in:
Nikita Popov 2021-06-08 14:31:55 +02:00
parent d818edeae2
commit d8165c2502
2 changed files with 35 additions and 2 deletions

23
Zend/tests/bug81104.phpt Normal file
View File

@ -0,0 +1,23 @@
--TEST--
Bug #81104: Warning: "Failed to set memory limit to ... bytes" emitted after exit in debug
--INI--
memory_limit=5M
report_memleaks=0
--FILE--
<?php
class X {
public $x;
public function __construct() { $this->x = [$this]; }
}
gc_disable();
ini_set('memory_limit', '10M');
$y = [];
for ($i = 0; $i < 10000; $i++) {
$y[] = new X();
}
$y[0]->y = &$y;
?>
===DONE===
--EXPECT--
===DONE===

View File

@ -303,8 +303,14 @@ static PHP_INI_MH(OnChangeMemoryLimit)
value = Z_L(1)<<30; /* effectively, no limit */
}
if (zend_set_memory_limit(value) == FAILURE) {
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;
/* 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;
}
}
PG(memory_limit) = value;
return SUCCESS;
@ -1963,6 +1969,10 @@ void php_request_shutdown(void *dummy)
shutdown_memory_manager(CG(unclean_shutdown) || !report_memleaks, 0);
} zend_end_try();
/* Reset memory limit, as the reset during INI_STAGE_DEACTIVATE may have failed.
* At this point, no memory beyond a single chunk should be in use. */
zend_set_memory_limit(PG(memory_limit));
/* 16. Deactivate Zend signals */
#ifdef ZEND_SIGNALS
zend_signal_deactivate();