diff --git a/Zend/tests/bug81070.phpt b/Zend/tests/bug81070.phpt new file mode 100644 index 00000000000..0dc45056e33 --- /dev/null +++ b/Zend/tests/bug81070.phpt @@ -0,0 +1,9 @@ +--TEST-- +Bug #81070 Setting memory limit to below current usage +--FILE-- + +--EXPECTF-- +Warning: Failed to set memory limit to 3145728 bytes (Current memory usage is %d bytes) in %s on line %d diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index 953fc4b25e5..c742ab2287e 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -2658,11 +2658,24 @@ ZEND_API char* ZEND_FASTCALL zend_strndup(const char *s, size_t length) return p; } +ZEND_API zend_result zend_set_memory_limit_ex(size_t memory_limit) +{ +#if ZEND_MM_LIMIT + if (memory_limit < ZEND_MM_CHUNK_SIZE) { + memory_limit = ZEND_MM_CHUNK_SIZE; + } + if (UNEXPECTED(memory_limit < AG(mm_heap)->real_size)) { + return FAILURE; + } + AG(mm_heap)->limit = memory_limit; +#endif + return SUCCESS; +} ZEND_API void zend_set_memory_limit(size_t memory_limit) { #if ZEND_MM_LIMIT - AG(mm_heap)->limit = (memory_limit >= ZEND_MM_CHUNK_SIZE) ? memory_limit : ZEND_MM_CHUNK_SIZE; + AG(mm_heap)->limit = memory_limit >= ZEND_MM_CHUNK_SIZE ? memory_limit : ZEND_MM_CHUNK_SIZE; #endif } diff --git a/Zend/zend_alloc.h b/Zend/zend_alloc.h index ef97766eb53..de450bbca2f 100644 --- a/Zend/zend_alloc.h +++ b/Zend/zend_alloc.h @@ -220,6 +220,7 @@ ZEND_API void * __zend_realloc(void *p, size_t len) ZEND_ATTRIBUTE_ALLOC_SIZE(2) #define pestrdup_rel(s, persistent) ((persistent)?strdup(s):estrdup_rel(s)) ZEND_API void zend_set_memory_limit(size_t memory_limit); +ZEND_API zend_result zend_set_memory_limit_ex(size_t memory_limit); ZEND_API void start_memory_manager(void); ZEND_API void shutdown_memory_manager(bool silent, bool full_shutdown); diff --git a/main/main.c b/main/main.c index 85ed029157a..8f7bf719c9b 100644 --- a/main/main.c +++ b/main/main.c @@ -266,12 +266,17 @@ static PHP_INI_MH(OnSetSerializePrecision) /* {{{ PHP_INI_MH */ static PHP_INI_MH(OnChangeMemoryLimit) { + size_t value; if (new_value) { - PG(memory_limit) = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); + value = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); } else { - PG(memory_limit) = Z_L(1)<<30; /* effectively, no limit */ + value = Z_L(1)<<30; /* effectively, no limit */ } - zend_set_memory_limit(PG(memory_limit)); + if (zend_set_memory_limit_ex(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; + } + PG(memory_limit) = value; return SUCCESS; } /* }}} */