Skip to content

Commit

Permalink
Limit stack size (#9104)
Browse files Browse the repository at this point in the history
  • Loading branch information
arnaud-lb authored Dec 16, 2022
1 parent dc54e04 commit a11c8a3
Show file tree
Hide file tree
Showing 41 changed files with 1,844 additions and 12 deletions.
1 change: 1 addition & 0 deletions .appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ environment:
#PDO_MYSQL_TEST_PASS: Password12!
#PGSQL_TEST_CONNSTR: "host=127.0.0.1 dbname=test port=5432 user=postgres password=Password12!"
#PDO_PGSQL_TEST_DSN: "pgsql:host=127.0.0.1 port=5432 dbname=test user=postgres password=Password12!"
STACK_LIMIT_DEFAULTS_CHECK: 1
#build permutations
matrix:
- THREAD_SAFE: 0
Expand Down
1 change: 1 addition & 0 deletions .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -201,4 +201,5 @@ freebsd_task:
tests_script:
- export SKIP_IO_CAPTURE_TESTS=1
- export CI_NO_IPV6=1
- export STACK_LIMIT_DEFAULTS_CHECK=1
- sapi/cli/php run-tests.php -P -q -j2 -g FAIL,BORK,LEAK,XLEAK --no-progress --offline --show-diff --show-slow 1000 --set-timeout 120 -d zend_extension=opcache.so
1 change: 1 addition & 0 deletions .github/actions/test-linux/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ runs:
export PDO_OCI_TEST_DSN="oci:dbname=localhost/XEPDB1;charset=AL32UTF8"
export SKIP_IO_CAPTURE_TESTS=1
export TEST_PHP_JUNIT=junit.out.xml
export STACK_LIMIT_DEFAULTS_CHECK=1
sapi/cli/php run-tests.php -P -q ${{ inputs.runTestsParameters }} \
-j$(/usr/bin/nproc) \
-g FAIL,BORK,LEAK,XLEAK \
Expand Down
1 change: 1 addition & 0 deletions .github/actions/test-macos/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ runs:
export SKIP_IO_CAPTURE_TESTS=1
export CI_NO_IPV6=1
export TEST_PHP_JUNIT=junit.out.xml
export STACK_LIMIT_DEFAULTS_CHECK=1
sapi/cli/php run-tests.php -P -q ${{ inputs.runTestsParameters }} \
-j$(sysctl -n hw.ncpu) \
-g FAIL,BORK,LEAK,XLEAK \
Expand Down
32 changes: 31 additions & 1 deletion Zend/Zend.m4
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,37 @@ _LT_AC_TRY_DLOPEN_SELF([
])
dnl Checks for library functions.
AC_CHECK_FUNCS(getpid kill sigsetjmp)
AC_CHECK_FUNCS(getpid kill sigsetjmp pthread_getattr_np pthread_attr_get_np pthread_get_stackaddr_np pthread_attr_getstack gettid)
dnl Test whether the stack grows downwards
dnl Assumes contiguous stack
AC_MSG_CHECKING(whether the stack grows downwards)
AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <stdint.h>
int (*volatile f)(uintptr_t);
int stack_grows_downwards(uintptr_t arg) {
int local;
return (uintptr_t)&local < arg;
}
int main() {
int local;
f = stack_grows_downwards;
return f((uintptr_t)&local) ? 0 : 1;
}
]])], [
AC_DEFINE([ZEND_STACK_GROWS_DOWNWARDS], 1, [Define if the stack grows downwards])
AC_DEFINE([ZEND_CHECK_STACK_LIMIT], 1, [Define if checking the stack limit is supported])
AC_MSG_RESULT(yes)
], [
AC_MSG_RESULT(no)
], [
AC_MSG_RESULT(no)
])
ZEND_CHECK_FLOAT_PRECISION
])
Expand Down
77 changes: 77 additions & 0 deletions Zend/tests/stack_limit/stack_limit_001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
--TEST--
Stack limit 001 - Stack limit checks with max_allowed_stack_size detection
--EXTENSIONS--
zend_test
--INI--
; The test may use a large amount of memory on systems with a large stack limit
memory_limit=2G
--FILE--
<?php

var_dump(zend_test_zend_call_stack_get());

class Test1 {
public function __destruct() {
new Test1;
}
}

class Test2 {
public function __clone() {
clone $this;
}
}

class Test3 {
public function __sleep()
{
serialize($this);
}
}

function replace() {
return preg_replace_callback('#.#', function () {
return replace();
}, 'x');
}

try {
new Test1;
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

try {
clone new Test2;
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

try {
serialize(new Test3);
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

try {
replace();
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

?>
--EXPECTF--
array(4) {
["base"]=>
string(%d) "0x%x"
["max_size"]=>
string(%d) "0x%x"
["position"]=>
string(%d) "0x%x"
["EG(stack_limit)"]=>
string(%d) "0x%x"
}
Maximum call stack size of %d bytes reached. Infinite recursion?
Maximum call stack size of %d bytes reached. Infinite recursion?
Maximum call stack size of %d bytes reached. Infinite recursion?
Maximum call stack size of %d bytes reached. Infinite recursion?
80 changes: 80 additions & 0 deletions Zend/tests/stack_limit/stack_limit_002.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
--TEST--
Stack limit 002 - Stack limit checks with max_allowed_stack_size detection (fibers)
--EXTENSIONS--
zend_test
--INI--
fiber.stack_size=512k
--FILE--
<?php

var_dump(zend_test_zend_call_stack_get());

class Test1 {
public function __destruct() {
new Test1;
}
}

class Test2 {
public function __clone() {
clone $this;
}
}

class Test3 {
public function __sleep()
{
serialize($this);
}
}

function replace() {
return preg_replace_callback('#.#', function () {
return replace();
}, 'x');
}

$fiber = new Fiber(function (): void {
try {
new Test1;
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

try {
clone new Test2;
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

try {
serialize(new Test3);
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

try {
replace();
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
});

$fiber->start();

?>
--EXPECTF--
array(4) {
["base"]=>
string(%d) "0x%x"
["max_size"]=>
string(%d) "0x%x"
["position"]=>
string(%d) "0x%x"
["EG(stack_limit)"]=>
string(%d) "0x%x"
}
Maximum call stack size of %d bytes reached. Infinite recursion?
Maximum call stack size of %d bytes reached. Infinite recursion?
Maximum call stack size of %d bytes reached. Infinite recursion?
Maximum call stack size of %d bytes reached. Infinite recursion?
62 changes: 62 additions & 0 deletions Zend/tests/stack_limit/stack_limit_003.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
--TEST--
Stack limit 003 - Stack limit checks with fixed max_allowed_stack_size
--EXTENSIONS--
zend_test
--INI--
zend.max_allowed_stack_size=128K
--FILE--
<?php

var_dump(zend_test_zend_call_stack_get());

class Test1 {
public function __destruct() {
new Test1;
}
}

class Test2 {
public function __clone() {
clone $this;
}
}

function replace() {
return preg_replace_callback('#.#', function () {
return replace();
}, 'x');
}

try {
new Test1;
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

try {
clone new Test2;
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

try {
replace();
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

?>
--EXPECTF--
array(4) {
["base"]=>
string(%d) "0x%x"
["max_size"]=>
string(%d) "0x%x"
["position"]=>
string(%d) "0x%x"
["EG(stack_limit)"]=>
string(%d) "0x%x"
}
Maximum call stack size of %d bytes reached. Infinite recursion?
Maximum call stack size of %d bytes reached. Infinite recursion?
Maximum call stack size of %d bytes reached. Infinite recursion?
50 changes: 50 additions & 0 deletions Zend/tests/stack_limit/stack_limit_004.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
--TEST--
Stack limit 004 - Stack limit checks with fixed max_allowed_stack_size (fibers)
--EXTENSIONS--
zend_test
--FILE--
<?php

var_dump(zend_test_zend_call_stack_get());

class Test1 {
public function __destruct() {
new Test1;
}
}

$callback = function (): int {
try {
new Test1;
} catch (Error $e) {
return count($e->getTrace());
}

throw new \Exception();
};

ini_set('fiber.stack_size', '400K');
$fiber = new Fiber($callback);
$fiber->start();
$depth1 = $fiber->getReturn();

ini_set('fiber.stack_size', '200K');
$fiber = new Fiber($callback);
$fiber->start();
$depth2 = $fiber->getReturn();

var_dump($depth1 > $depth2);

?>
--EXPECTF--
array(4) {
["base"]=>
string(%d) "0x%x"
["max_size"]=>
string(%d) "0x%x"
["position"]=>
string(%d) "0x%x"
["EG(stack_limit)"]=>
string(%d) "0x%x"
}
bool(true)
Loading

0 comments on commit a11c8a3

Please sign in to comment.