-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Fix #81070: Integer underflow when memory limit is exceeded #7040
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
Conversation
Thanks for the PR! I don't think this qualifies as security issue, so please target PHP-7.4. Also note that the test fails due to slight differences in the error message. |
Targeted 7.4 and fixed the test for non-debug builds. Thanks. |
The AppVeyor failure is because the PR is still build against PHP-7.3, since you didn't rebase onto PHP-7.4 before changing the branch. IMO not a real issue. |
I think a better way to approach this is to forbid reducing the memory limit below the current usage. That would point out the error at the point it is introduced, and avoid additional checks in the allocator. It should be possible to do this by adjusting zend_set_memory_limit to return FAILURE if the limit is below current usage and checking the return value in Line 274 in c40231a
|
👍 I'll see if I can implement it like that this weekend. |
…FAIL. This old bugfix is not working as intended. The memory limit in main's `PG(memory_limit)` differs from the one in zend_alloc. In zend_alloc the `AG(mm_heap)->limit` is defined as `max(passed_value, ZEND_MM_CHUNK_SIZE)`. The check made in an unclean shutdown will never be true unless the memory limit is lower than ZEND_MM_CHUNK_SIZE, which happened to be the case in the test. https://bugs.php.net/bug.php?id=45392 php@fcc0fdd
Reducing the memory limit below the current memory has probably not been the intention of this test.
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 return a warning.
PR now contains the other approach as suggested by nikic: zend_alloc's The only other call to zend_set_memory_limit within A warning is used instead of an error. I think that makes the most sense, but I'm not sure if there are any similar cases which do throw an error. The warning message contains a fairly generic error without a mention of the target memory being lower than the current. The error message could be moved into the I'm not certain if we have to attempt to run When merging into 8.0/master you'll encounter a conflict with fa8d9b1, it'll probably be ok. ============ By forbidding the limit to be lowered below the current memory two other issues have also surfaced where this was (likely) done incorrectly in tests. One is a test which sets the limit to 512KB, lower than the initial memory usage. I have increased the memory used in this test. Another is an ancient test and accompanying fix that don't have the correct behaviour. For this PR I have fixed the test so that it will fail as it probably should and marked it as XFAIL. The problem is that the memory limit in main's It gets beyond the scope of this particular PR but the following code in
Removing the check on the memory limit (and error type?) entirely makes a lot of sense to me, but I can imagine that it's better to apply such a change on master instead. |
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.
For PHP-7.4 I've landed a modified version of this patch in 1b3b5c9, which makes rounds up the limit to the chunk size, and thus avoids impacting those two tests. Let's do that change only for master. For PHP-8.0 I had to introduce a |
Remaining change together with more test adjustments landed in master as 3a4ea6c. |
The output buffering issue should be addressed by e9b0051. I've moved discarding output into the error handler, which allows us to print the memory limit error to normal output. Otherwise you don't see anything at all unless you do something like I think with that, all issues here are resolved. |
Guess our system(s) was doing some naughty things since we are noticing crashes after bumping up to 7.4.21. I guess we were trying to ini set like 512M, but the system was already running around ~600M and now the warning bubbles up to something not handled very well. Very interesting background after following the 7.4.21 change log to a related entry about memory to this. |
This wasn't an issue in dev, but it was breaking in CI with the error: ``` Failed to set memory limit to 1048576 bytes ``` I'm guessing the problem is related to the backwards-incompatible change in PHP 7.4: https://php.watch/versions/7.4/memory_limit-lt-2m php/php-src#7040
This wasn't an issue in dev, but it was breaking in CI with the error: ``` Failed to set memory limit to 1048576 bytes ``` I'm guessing the problem is related to the backwards-incompatible change in PHP 7.4: https://php.watch/versions/7.4/memory_limit-lt-2m php/php-src#7040
When the memory limit is reduced using an
ini_set("memory_limit", ..)
below the currently allocated memory. Further allocations should
cause a memory limit exceeded error.
This fixes the regression introduced in 7.2.23
I have targeted the 7.3 branch as this bug allows for unlimited memory usage in some scenarios.