- URL: https://www.laruence.com/en/2009/11/27/1164.html
- Please include attribution when republishing.
In PHP 5.2x, memory_limit could not be set to any value above 4G, because zend_atoi was chosen by mistake.
A colleague shared a problem with me today (thanks to yanmi): a piece of code (PHP 5.2.11, Linux/X86_64) exhausts memory when memory_limit is set to 4096M, but not when it is set to 4095M. A strange problem indeed.
So what's going on?
The cause is simple enough. In OnChangeMemoryLimit, the handler for the memory_limit setting defined in PHPSRC/main.c, the machine's word length is never checked; zend_atoi is used uniformly to turn the string into a number. This was already fixed in PHP 5.3 (switched to zend_atol):
static PHP_INI_MH(OnChangeMemoryLimit)
{
if (new_value) {
PG(memory_limit) = zend_atoi(new_value, new_value_length);
} else {
PG(memory_limit) = 1<<30; /* effectively, no limit */
}
return zend_set_memory_limit(PG(memory_limit));
}
And, as the name suggests, atoi converts to an integer. 4096M is 2 to the power of 32, so it overflows and wraps around to 0. Here is the zend_atoi code:
ZEND_API int zend_atoi(const char *str, int str_len)
{
int retval;
if (!str_len) {
str_len = strlen(str);
}
retval = strtol(str, NULL, 0);
if (str_len>0) {
switch (str[str_len-1]) {
case 'g':
case 'G':
retval *= 1024;
/* break intentionally missing */
case 'm':
case 'M':
retval *= 1024;
/* break intentionally missing */
case 'k':
case 'K':
retval *= 1024;
break;
}
}
return retval;
}
Finally, in zend_set_memory_limit, memory_limit is wrongly set to mm_heap's block_size, so the result is certainly far smaller than the 4096M you expected:
.... AG(mm_heap)->limit = (memory_limit >= AG(mm_heap)->block_size) ? memory_limit : AG(mm_heap)->block_size; ...
Lastly: on a 32-bit machine this isn't really a bug. But plenty of machines are 64-bit these days and maximum memory is no longer capped at 4GB — PHP has to keep up with the times.
PS: reading other people's code pays off. Today I also learned the word "intentionally", ^_^.
Be First to Comment