mirror of
https://github.com/php/php-src.git
synced 2024-09-21 09:57:23 +00:00
Fix stack limit on ASAN/MSAN (#14771)
Increase the reserved stack size in ASAN builds, as instrumentation use more stack. Increase the max allowed stack size in some tests, and enable these tests under ASAN. Use __builtin_frame_address(0), instead of some stack variable, when we need a stack address, as ASAN may store local variables outside of the real stack.
This commit is contained in:
parent
e63e1afd84
commit
0bd260218b
15
Zend/Zend.m4
15
Zend/Zend.m4
@ -216,15 +216,26 @@ AC_DEFUN([ZEND_CHECK_STACK_DIRECTION],
|
||||
int (*volatile f)(uintptr_t);
|
||||
|
||||
int stack_grows_downwards(uintptr_t arg) {
|
||||
#if defined(__has_builtin) && __has_builtin(__builtin_frame_address)
|
||||
uintptr_t addr = (uintptr_t)__builtin_frame_address(0);
|
||||
#else
|
||||
int local;
|
||||
return (uintptr_t)&local < arg;
|
||||
uintptr_t addr = (uintptr_t)&local;
|
||||
#endif
|
||||
|
||||
return addr < arg;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
#if defined(__has_builtin) && __has_builtin(__builtin_frame_address)
|
||||
uintptr_t addr = (uintptr_t)__builtin_frame_address(0);
|
||||
#else
|
||||
int local;
|
||||
uintptr_t addr = (uintptr_t)&local;
|
||||
#endif
|
||||
|
||||
f = stack_grows_downwards;
|
||||
return f((uintptr_t)&local) ? 0 : 1;
|
||||
return f(addr) ? 0 : 1;
|
||||
}])],
|
||||
[php_cv_have_stack_limit=yes],
|
||||
[php_cv_have_stack_limit=no],
|
||||
|
@ -3,7 +3,6 @@ Stack limit 001 - Stack limit checks with max_allowed_stack_size detection
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!function_exists('zend_test_zend_call_stack_get')) die("skip zend_test_zend_call_stack_get() is not available");
|
||||
if (getenv('SKIP_MSAN')) die("skip msan requires a considerably higher zend.reserved_stack_size due to instrumentation");
|
||||
?>
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
|
@ -3,7 +3,6 @@ Stack limit 002 - Stack limit checks with max_allowed_stack_size detection (fibe
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!function_exists('zend_test_zend_call_stack_get')) die("skip zend_test_zend_call_stack_get() is not available");
|
||||
if (getenv('SKIP_MSAN')) die("skip msan requires a considerably higher zend.reserved_stack_size due to instrumentation");
|
||||
?>
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
|
@ -7,7 +7,7 @@ if (!function_exists('zend_test_zend_call_stack_get')) die("skip zend_test_zend_
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
--INI--
|
||||
zend.max_allowed_stack_size=256K
|
||||
zend.max_allowed_stack_size=512K
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
|
@ -27,12 +27,12 @@ $callback = function (): int {
|
||||
throw new \Exception();
|
||||
};
|
||||
|
||||
ini_set('fiber.stack_size', '400K');
|
||||
ini_set('fiber.stack_size', '1M');
|
||||
$fiber = new Fiber($callback);
|
||||
$fiber->start();
|
||||
$depth1 = $fiber->getReturn();
|
||||
|
||||
ini_set('fiber.stack_size', '200K');
|
||||
ini_set('fiber.stack_size', '512K');
|
||||
$fiber = new Fiber($callback);
|
||||
$fiber->start();
|
||||
$depth2 = $fiber->getReturn();
|
||||
|
@ -3,7 +3,6 @@ Stack limit 006 - env size affects __libc_stack_end
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!function_exists('zend_test_zend_call_stack_get')) die("skip zend_test_zend_call_stack_get() is not available");
|
||||
if (getenv('SKIP_MSAN')) die("skip msan requires a considerably higher zend.reserved_stack_size due to instrumentation");
|
||||
?>
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
|
@ -7,7 +7,7 @@ if (!function_exists('zend_test_zend_call_stack_get')) die("skip zend_test_zend_
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
--INI--
|
||||
zend.max_allowed_stack_size=256K
|
||||
zend.max_allowed_stack_size=512K
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
|
@ -7,7 +7,7 @@ if (!function_exists('zend_test_zend_call_stack_get')) die("skip zend_test_zend_
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
--INI--
|
||||
zend.max_allowed_stack_size=256K
|
||||
zend.max_allowed_stack_size=512K
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
|
@ -3,7 +3,6 @@ Stack limit 009 - Check that we can actually use all the stack
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!function_exists('zend_test_zend_call_stack_get')) die("skip zend_test_zend_call_stack_get() is not available");
|
||||
if (getenv('SKIP_MSAN')) die("skip msan requires a considerably higher zend.reserved_stack_size due to instrumentation");
|
||||
?>
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
|
@ -7,24 +7,27 @@ if (!function_exists('zend_test_zend_call_stack_get')) die("skip zend_test_zend_
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
--INI--
|
||||
zend.max_allowed_stack_size=256K
|
||||
zend.max_allowed_stack_size=512K
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
var_dump(zend_test_zend_call_stack_get());
|
||||
|
||||
class Test1 {
|
||||
public function __destruct() {
|
||||
new Test1;
|
||||
}
|
||||
}
|
||||
|
||||
function replace() {
|
||||
function replace2() {
|
||||
return preg_replace_callback('#.#', function () {
|
||||
replace2();
|
||||
}, 'x');
|
||||
}
|
||||
function replace() {
|
||||
static $once = false;
|
||||
return preg_replace_callback('#.#', function () use (&$once) {
|
||||
try {
|
||||
replace();
|
||||
} finally {
|
||||
new Test1();
|
||||
if (!$once) {
|
||||
$once = true;
|
||||
replace2();
|
||||
}
|
||||
}
|
||||
}, 'x');
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ if (!function_exists('zend_test_zend_call_stack_get')) die("skip zend_test_zend_
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
--INI--
|
||||
zend.max_allowed_stack_size=256K
|
||||
zend.max_allowed_stack_size=512K
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
|
13
Zend/tests/stack_limit/stack_limit_013.inc
Normal file
13
Zend/tests/stack_limit/stack_limit_013.inc
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
if (!class_exists("constructs_in_destructor")) {
|
||||
class constructs_in_destructor {
|
||||
public function __destruct() {
|
||||
$a = new constructs_in_destructor;
|
||||
$time = '';
|
||||
require(__FILE__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$a = new constructs_in_destructor;
|
13
Zend/tests/stack_limit/stack_limit_014.inc
Normal file
13
Zend/tests/stack_limit/stack_limit_014.inc
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
if (!class_exists("constructs_in_destructor")) {
|
||||
class constructs_in_destructor {
|
||||
public function __destruct() {
|
||||
$a = new constructs_in_destructor;
|
||||
$time = '';
|
||||
require(__FILE__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$a = new constructs_in_destructor;
|
23
Zend/tests/stack_limit/stack_limit_014.phpt
Normal file
23
Zend/tests/stack_limit/stack_limit_014.phpt
Normal file
@ -0,0 +1,23 @@
|
||||
--TEST--
|
||||
Stack limit 014 - Fuzzer
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!function_exists('zend_test_zend_call_stack_get')) die("skip zend_test_zend_call_stack_get() is not available");
|
||||
?>
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
--INI--
|
||||
; The test may use a large amount of memory on systems with a large stack limit
|
||||
memory_limit=1G
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
try {
|
||||
require __DIR__.'/stack_limit_014.inc';
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
%S%rMaximum call stack size of [0-9]+ bytes \(zend\.max_allowed_stack_size - zend\.reserved_stack_size\) reached|Allowed memory size of [0-9]+ bytes exhausted%r%s
|
@ -214,6 +214,12 @@ static ZEND_INI_MH(OnUpdateReservedStackSize) /* {{{ */
|
||||
zend_ulong min = 32*1024;
|
||||
#endif
|
||||
|
||||
#ifdef __SANITIZE_ADDRESS__
|
||||
/* AddressSanitizer and MemorySanitizer use more stack due to
|
||||
* instrumentation */
|
||||
min *= 10;
|
||||
#endif
|
||||
|
||||
if (size == 0) {
|
||||
size = min;
|
||||
} else if (size < min) {
|
||||
|
@ -176,7 +176,7 @@ static bool zend_call_stack_get_linux_proc_maps(zend_call_stack *stack)
|
||||
{
|
||||
FILE *f;
|
||||
char buffer[4096];
|
||||
uintptr_t addr_on_stack = (uintptr_t)&buffer;
|
||||
uintptr_t addr_on_stack = (uintptr_t) zend_call_stack_position();
|
||||
uintptr_t start, end, prev_end = 0;
|
||||
size_t max_size;
|
||||
bool found = false;
|
||||
@ -610,7 +610,7 @@ static bool zend_call_stack_get_netbsd_vm(zend_call_stack *stack, void **ptr)
|
||||
struct kinfo_vmentry *entry;
|
||||
size_t len, max_size;
|
||||
char buffer[4096];
|
||||
uintptr_t addr_on_stack = (uintptr_t)&buffer;
|
||||
uintptr_t addr_on_stack = (uintptr_t) zend_call_stack_position();
|
||||
int mib[5] = { CTL_VM, VM_PROC, VM_PROC_MAP, getpid(), sizeof(struct kinfo_vmentry) };
|
||||
bool found = false;
|
||||
struct rlimit rlim;
|
||||
@ -691,7 +691,7 @@ static bool zend_call_stack_get_solaris_pthread(zend_call_stack *stack)
|
||||
static bool zend_call_stack_get_solaris_proc_maps(zend_call_stack *stack)
|
||||
{
|
||||
char buffer[4096];
|
||||
uintptr_t addr_on_stack = (uintptr_t)&buffer;
|
||||
uintptr_t addr_on_stack = (uintptr_t) zend_call_stack_position();
|
||||
bool found = false, r = false;
|
||||
struct ps_prochandle *proc;
|
||||
prmap_t *map, *orig;
|
||||
|
@ -103,9 +103,14 @@ static void zend_compile_assign(znode *result, zend_ast *ast);
|
||||
#ifdef ZEND_CHECK_STACK_LIMIT
|
||||
zend_never_inline static void zend_stack_limit_error(void)
|
||||
{
|
||||
size_t max_stack_size = 0;
|
||||
if ((uintptr_t) EG(stack_base) > (uintptr_t) EG(stack_limit)) {
|
||||
max_stack_size = (size_t) ((uintptr_t) EG(stack_base) - (uintptr_t) EG(stack_limit));
|
||||
}
|
||||
|
||||
zend_error_noreturn(E_COMPILE_ERROR,
|
||||
"Maximum call stack size of %zu bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached during compilation. Try splitting expression",
|
||||
(size_t) ((uintptr_t) EG(stack_base) - (uintptr_t) EG(stack_limit)));
|
||||
max_stack_size);
|
||||
}
|
||||
|
||||
static void zend_check_stack_limit(void)
|
||||
|
@ -2460,8 +2460,13 @@ static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_use_new_element_for_s
|
||||
#ifdef ZEND_CHECK_STACK_LIMIT
|
||||
static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_call_stack_size_error(void)
|
||||
{
|
||||
size_t max_stack_size = 0;
|
||||
if ((uintptr_t) EG(stack_base) > (uintptr_t) EG(stack_limit)) {
|
||||
max_stack_size = (size_t) ((uintptr_t) EG(stack_base) - (uintptr_t) EG(stack_limit));
|
||||
}
|
||||
|
||||
zend_throw_error(NULL, "Maximum call stack size of %zu bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?",
|
||||
(size_t) ((uintptr_t) EG(stack_base) - (uintptr_t) EG(stack_limit)));
|
||||
max_stack_size);
|
||||
}
|
||||
#endif /* ZEND_CHECK_STACK_LIMIT */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user