diff --git a/.appveyor.yml b/.appveyor.yml index 7567578af258d..350fac2c026bb 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -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 diff --git a/.cirrus.yml b/.cirrus.yml index 10558901ad167..a7676803d1fe3 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -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 diff --git a/.github/actions/test-linux/action.yml b/.github/actions/test-linux/action.yml index 2c1d53f4d6da5..c505a45c9aa74 100644 --- a/.github/actions/test-linux/action.yml +++ b/.github/actions/test-linux/action.yml @@ -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 \ diff --git a/.github/actions/test-macos/action.yml b/.github/actions/test-macos/action.yml index 3deafde06200c..8284b8905ef74 100644 --- a/.github/actions/test-macos/action.yml +++ b/.github/actions/test-macos/action.yml @@ -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 \ diff --git a/Zend/Zend.m4 b/Zend/Zend.m4 index fd00dc7270de5..3bd30bf78e984 100644 --- a/Zend/Zend.m4 +++ b/Zend/Zend.m4 @@ -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 + +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 ]) diff --git a/Zend/tests/stack_limit/stack_limit_001.phpt b/Zend/tests/stack_limit/stack_limit_001.phpt new file mode 100644 index 0000000000000..626ec3fe570fa --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_001.phpt @@ -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-- +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? diff --git a/Zend/tests/stack_limit/stack_limit_002.phpt b/Zend/tests/stack_limit/stack_limit_002.phpt new file mode 100644 index 0000000000000..2459df3649083 --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_002.phpt @@ -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-- +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? diff --git a/Zend/tests/stack_limit/stack_limit_003.phpt b/Zend/tests/stack_limit/stack_limit_003.phpt new file mode 100644 index 0000000000000..51bf51f2ab26b --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_003.phpt @@ -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-- +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? diff --git a/Zend/tests/stack_limit/stack_limit_004.phpt b/Zend/tests/stack_limit/stack_limit_004.phpt new file mode 100644 index 0000000000000..a3da4664edb03 --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_004.phpt @@ -0,0 +1,50 @@ +--TEST-- +Stack limit 004 - Stack limit checks with fixed max_allowed_stack_size (fibers) +--EXTENSIONS-- +zend_test +--FILE-- +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) diff --git a/Zend/tests/stack_limit/stack_limit_005.phpt b/Zend/tests/stack_limit/stack_limit_005.phpt new file mode 100644 index 0000000000000..6e50bd34e7e8e --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_005.phpt @@ -0,0 +1,64 @@ +--TEST-- +Stack limit 005 - Internal stack limit check in zend_compile_expr() +--EXTENSIONS-- +zend_test +--INI-- +zend.max_allowed_stack_size=128K +--FILE-- +f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() +; + +--EXPECTF-- +Fatal error: Maximum call stack size of %d bytes reached during compilation. Try splitting expression in %s on line %d diff --git a/Zend/tests/stack_limit/stack_limit_006.phpt b/Zend/tests/stack_limit/stack_limit_006.phpt new file mode 100644 index 0000000000000..61da8b9dab04c --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_006.phpt @@ -0,0 +1,320 @@ +--TEST-- +Stack limit 006 - env size affects __libc_stack_end +--EXTENSIONS-- +zend_test +--INI-- +; TODO +memory_limit=2G +--ENV-- +ENV001=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV002=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV003=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV004=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV005=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV006=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV007=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV008=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV009=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV010=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV011=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV012=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV013=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV014=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV015=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV016=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV017=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV018=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV019=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV020=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV021=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV022=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV023=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV024=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV025=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV026=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV027=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV028=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV029=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV030=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV031=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV032=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV033=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV034=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV035=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV036=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV037=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV038=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV039=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV040=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV041=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV042=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV043=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV044=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV045=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV046=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV047=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV048=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV049=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV050=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV051=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV052=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV053=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV054=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV055=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV056=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV057=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV058=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV059=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV060=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV061=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV062=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV063=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV064=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV065=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV066=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV067=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV068=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV069=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV070=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV071=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV072=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV073=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV074=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV075=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV076=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV077=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV078=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV079=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV080=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV081=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV082=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV083=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV084=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV085=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV086=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV087=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV088=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV089=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV090=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV091=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV092=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV093=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV094=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV095=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV096=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV097=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV098=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV099=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV100=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV101=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV102=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV103=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV104=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV105=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV106=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV107=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV108=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV109=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV110=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV111=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV112=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV113=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV114=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV115=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV116=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV117=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV118=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV119=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV120=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV121=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV122=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV123=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV124=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV125=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV126=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV127=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV128=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV129=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV130=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV131=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV132=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV133=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV134=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV135=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV136=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV137=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV138=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV139=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV140=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV141=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV142=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV143=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV144=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV145=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV146=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV147=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV148=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV149=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV150=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV151=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV152=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV153=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV154=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV155=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV156=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV157=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV158=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV159=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV160=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV161=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV162=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV163=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV164=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV165=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV166=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV167=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV168=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV169=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV170=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV171=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV172=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV173=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV174=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV175=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV176=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV177=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV178=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV179=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV180=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV181=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV182=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV183=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV184=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV185=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV186=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV187=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV188=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV189=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV190=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV191=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV192=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV193=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV194=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV195=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV196=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV197=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV198=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV199=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV200=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV201=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV202=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV203=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV204=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV205=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV206=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV207=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV208=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV209=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV210=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV211=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV212=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV213=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV214=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV215=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV216=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV217=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV218=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV219=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV220=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV221=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV222=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV223=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV224=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV225=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV226=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV227=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV228=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV229=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV230=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV231=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV232=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV233=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV234=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV235=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV236=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV237=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV238=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV239=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV240=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV241=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV242=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV243=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV244=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV245=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV246=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV247=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV248=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV249=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV250=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV251=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV252=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV253=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV254=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV255=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +ENV256=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +--FILE-- +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? diff --git a/Zend/tests/stack_limit/stack_limit_007.phpt b/Zend/tests/stack_limit/stack_limit_007.phpt new file mode 100644 index 0000000000000..7994bb66f1e3b --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_007.phpt @@ -0,0 +1,41 @@ +--TEST-- +Stack limit 007 - Exception handling +--EXTENSIONS-- +zend_test +--INI-- +zend.max_allowed_stack_size=128K +--FILE-- +getMessage(), "\n"; + // We should not enter the catch block if we haven't executed at + // least one op in the try block + printf("Try executed: %d\n", $tryExecuted ?? 0); + } + }, 'x'); +} + +replace(); + +?> +--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? +Try executed: 1 diff --git a/Zend/tests/stack_limit/stack_limit_008.phpt b/Zend/tests/stack_limit/stack_limit_008.phpt new file mode 100644 index 0000000000000..9609667bf3be7 --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_008.phpt @@ -0,0 +1,54 @@ +--TEST-- +Stack limit 008 - Exception handling +--EXTENSIONS-- +zend_test +--INI-- +zend.max_allowed_stack_size=128K +--FILE-- +getMessage(); + } + } + }, 'x'); +} + +function replace2() { + return preg_replace_callback('#.#', function () { + try { + return ''; + } finally { + // We should not enter the finally block if we haven't executed at + // least one op in the try block + echo "Finally block: This should not execute\n"; + } + }, 'x'); +} + +replace(); + +?> +--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" +} +Will throw: +Maximum call stack size of %d bytes reached. Infinite recursion? diff --git a/Zend/tests/stack_limit/stack_limit_009.phpt b/Zend/tests/stack_limit/stack_limit_009.phpt new file mode 100644 index 0000000000000..08f14495e4370 --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_009.phpt @@ -0,0 +1,24 @@ +--TEST-- +Stack limit 009 - Check that we can actually use all the stack +--EXTENSIONS-- +zend_test +--FILE-- + +--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" +} +int(%d) diff --git a/Zend/tests/stack_limit/stack_limit_010.phpt b/Zend/tests/stack_limit/stack_limit_010.phpt new file mode 100644 index 0000000000000..c9ca8c7d7f743 --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_010.phpt @@ -0,0 +1,48 @@ +--TEST-- +Stack limit 010 - Check stack size detection against known defaults +--EXTENSIONS-- +zend_test +--SKIPIF-- + +--FILE-- + 8*1024*1024, + 'FreeBSD' => match(php_uname('m')) { + 'amd64' => 512*1024*1024 - 4096, + 'i386' => 64*1024*1024 - 4096, + }, + 'Linux' => match (getenv('GITHUB_ACTIONS')) { + 'true' => 16*1024*1024, // https://github.com/actions/runner-images/pull/3328 + default => 8*1024*1024, + }, + 'Windows NT' => 67108864 - 4*4096, // Set by sapi/cli/config.w32 +}; + +printf("Expected max_size: 0x%x\n", $expectedMaxSize); +printf("Actual max_size: %s\n", $stack['max_size']); + +var_dump($stack['max_size'] === sprintf('0x%x', $expectedMaxSize)); + +?> +--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" +} +Expected max_size: 0x%x +Actual max_size: 0x%x +bool(true) diff --git a/Zend/tests/stack_limit/stack_limit_011.phpt b/Zend/tests/stack_limit/stack_limit_011.phpt new file mode 100644 index 0000000000000..3c5daf59f6b66 --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_011.phpt @@ -0,0 +1,48 @@ +--TEST-- +Stack limit 011 - Stack limit exhaustion during unwinding +--EXTENSIONS-- +zend_test +--INI-- +zend.max_allowed_stack_size=128K +--FILE-- +getMessage(), "\n"; + echo 'Previous: ', $e->getPrevious()->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? +Previous: Maximum call stack size of %d bytes reached. Infinite recursion? diff --git a/Zend/tests/stack_limit/stack_limit_012.inc b/Zend/tests/stack_limit/stack_limit_012.inc new file mode 100644 index 0000000000000..f6ad9c7428a90 --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_012.inc @@ -0,0 +1,54 @@ +f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() + ->f()->f()->f()->f()->f()->f()->f()->f()->f()->f() +; diff --git a/Zend/tests/stack_limit/stack_limit_012.phpt b/Zend/tests/stack_limit/stack_limit_012.phpt new file mode 100644 index 0000000000000..c4920a928d62b --- /dev/null +++ b/Zend/tests/stack_limit/stack_limit_012.phpt @@ -0,0 +1,37 @@ +--TEST-- +Stack limit 012 - Stack limit exhaustion during unwinding +--EXTENSIONS-- +zend_test +--INI-- +zend.max_allowed_stack_size=128K +--FILE-- + +--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" +} + +Fatal error: Maximum call stack size of %d bytes reached during compilation. Try splitting expression in %s on line %d diff --git a/Zend/zend.c b/Zend/zend.c index 46a0e1b4c0ea3..0eec5f89019d9 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -35,6 +35,7 @@ #include "zend_attributes.h" #include "zend_observer.h" #include "zend_fibers.h" +#include "zend_call_stack.h" #include "Optimizer/zend_optimizer.h" static size_t global_map_ptr_last = 0; @@ -173,6 +174,52 @@ static ZEND_INI_MH(OnSetExceptionStringParamMaxLen) /* {{{ */ } /* }}} */ +#ifdef ZEND_CHECK_STACK_LIMIT +static ZEND_INI_MH(OnUpdateMaxAllowedStackSize) /* {{{ */ +{ + zend_long size = zend_ini_parse_quantity_warn(new_value, entry->name); + + if (size < ZEND_MAX_ALLOWED_STACK_SIZE_UNCHECKED) { + zend_error(E_WARNING, "Invalid \"%s\" setting. Value must be >= %d, but got " ZEND_LONG_FMT, + ZSTR_VAL(entry->name), ZEND_MAX_ALLOWED_STACK_SIZE_UNCHECKED, size); + return FAILURE; + } + + EG(max_allowed_stack_size) = size; + + return SUCCESS; +} +/* }}} */ + +static ZEND_INI_MH(OnUpdateReservedStackSize) /* {{{ */ +{ + zend_ulong size = zend_ini_parse_uquantity_warn(new_value, entry->name); + + /* Min value accounts for alloca, PCRE2 START_FRAMES_SIZE, and some buffer + * for normal function calls. + * We could reduce this on systems without alloca if we also add stack size + * checks before pcre2_match(). */ +#ifdef ZEND_ALLOCA_MAX_SIZE + zend_ulong min = ZEND_ALLOCA_MAX_SIZE + 16*1024; +#else + zend_ulong min = 32*1024; +#endif + + if (size == 0) { + size = min; + } else if (size < min) { + zend_error(E_WARNING, "Invalid \"%s\" setting. Value must be >= " ZEND_ULONG_FMT ", but got " ZEND_ULONG_FMT "\n", + ZSTR_VAL(entry->name), min, size); + return FAILURE; + } + + EG(reserved_stack_size) = size; + + return SUCCESS; +} +/* }}} */ +#endif /* ZEND_CHECK_STACK_LIMIT */ + static ZEND_INI_MH(OnUpdateFiberStackSize) /* {{{ */ { if (new_value) { @@ -203,6 +250,12 @@ ZEND_INI_BEGIN() STD_ZEND_INI_BOOLEAN("zend.exception_ignore_args", "0", ZEND_INI_ALL, OnUpdateBool, exception_ignore_args, zend_executor_globals, executor_globals) STD_ZEND_INI_ENTRY("zend.exception_string_param_max_len", "15", ZEND_INI_ALL, OnSetExceptionStringParamMaxLen, exception_string_param_max_len, zend_executor_globals, executor_globals) STD_ZEND_INI_ENTRY("fiber.stack_size", NULL, ZEND_INI_ALL, OnUpdateFiberStackSize, fiber_stack_size, zend_executor_globals, executor_globals) +#ifdef ZEND_CHECK_STACK_LIMIT + /* The maximum allowed call stack size. 0: auto detect, -1: no limit. For fibers, this is fiber.stack_size. */ + STD_ZEND_INI_ENTRY("zend.max_allowed_stack_size", "0", ZEND_INI_SYSTEM, OnUpdateMaxAllowedStackSize, max_allowed_stack_size, zend_executor_globals, executor_globals) + /* Substracted from the max allowed stack size, as a buffer, when checking for overflow. 0: auto detect. */ + STD_ZEND_INI_ENTRY("zend.reserved_stack_size", "0", ZEND_INI_SYSTEM, OnUpdateReservedStackSize, reserved_stack_size, zend_executor_globals, executor_globals) +#endif ZEND_INI_END() @@ -796,6 +849,10 @@ static void executor_globals_ctor(zend_executor_globals *executor_globals) /* {{ executor_globals->record_errors = false; executor_globals->num_errors = 0; executor_globals->errors = NULL; +#ifdef ZEND_CHECK_STACK_LIMIT + executor_globals->stack_limit = (void*)0; + executor_globals->stack_base = (void*)0; +#endif } /* }}} */ @@ -817,6 +874,9 @@ static void zend_new_thread_end_handler(THREAD_T thread_id) /* {{{ */ { zend_copy_ini_directives(); zend_ini_refresh_caches(ZEND_INI_STAGE_STARTUP); +#ifdef ZEND_CHECK_STACK_LIMIT + zend_call_stack_init(); +#endif } /* }}} */ #endif @@ -982,7 +1042,7 @@ void zend_startup(zend_utility_functions *utility_functions) /* {{{ */ CG(map_ptr_base) = ZEND_MAP_PTR_BIASED_BASE(NULL); CG(map_ptr_size) = 0; CG(map_ptr_last) = 0; -#endif +#endif /* ZTS */ EG(error_reporting) = E_ALL & ~E_NOTICE; zend_interned_strings_init(); @@ -1077,6 +1137,10 @@ zend_result zend_post_startup(void) /* {{{ */ global_map_ptr_last = CG(map_ptr_last); #endif +#ifdef ZEND_CHECK_STACK_LIMIT + zend_call_stack_init(); +#endif + return SUCCESS; } /* }}} */ diff --git a/Zend/zend_call_stack.c b/Zend/zend_call_stack.c new file mode 100644 index 0000000000000..dadaa60dcb208 --- /dev/null +++ b/Zend/zend_call_stack.c @@ -0,0 +1,457 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Arnaud Le Blanc | + +----------------------------------------------------------------------+ +*/ + +/* Inspired from Chromium's stack_util.cc */ + +#include "zend.h" +#include "zend_globals.h" +#include "zend_portability.h" +#include "zend_call_stack.h" +#include +#ifdef ZEND_WIN32 +# include +# include +#else /* ZEND_WIN32 */ +# include +# ifdef HAVE_UNISTD_H +# include +# endif +# ifdef HAVE_SYS_TYPES_H +# include +# endif +#endif /* ZEND_WIN32 */ +#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) +# include +#endif +#ifdef __FreeBSD__ +# include +# include +# include +# include +#endif +#ifdef __linux__ +#include +#endif + +#ifdef ZEND_CHECK_STACK_LIMIT + +/* Called once per process or thread */ +ZEND_API void zend_call_stack_init(void) { + if (!zend_call_stack_get(&EG(call_stack))) { + EG(call_stack) = (zend_call_stack){0}; + } + + switch (EG(max_allowed_stack_size)) { + case ZEND_MAX_ALLOWED_STACK_SIZE_DETECT: { + void *base = EG(call_stack).base; + size_t size = EG(call_stack).max_size; + if (UNEXPECTED(base == (void*)0)) { + base = zend_call_stack_position(); + size = zend_call_stack_default_size(); + /* base is not the actual stack base */ + size -= 32 * 1024; + } + EG(stack_base) = base; + EG(stack_limit) = zend_call_stack_limit(base, size, EG(reserved_stack_size)); + break; + } + case ZEND_MAX_ALLOWED_STACK_SIZE_UNCHECKED: { + EG(stack_base) = (void*)0; + EG(stack_limit) = (void*)0; + break; + } + default: { + ZEND_ASSERT(EG(max_allowed_stack_size) > 0); + void *base = EG(call_stack).base; + if (UNEXPECTED(base == (void*)0)) { + base = zend_call_stack_position(); + } + EG(stack_base) = base; + EG(stack_limit) = zend_call_stack_limit(base, EG(max_allowed_stack_size), EG(reserved_stack_size)); + break; + } + } +} + +#ifdef __linux__ +static bool zend_call_stack_is_main_thread(void) { +# ifdef HAVE_GETTID + return getpid() == gettid(); +# else + return getpid() == syscall(SYS_gettid); +# endif +} + +# ifdef HAVE_PTHREAD_GETATTR_NP +static bool zend_call_stack_get_linux_pthread(zend_call_stack *stack) +{ + pthread_attr_t attr; + int error; + void *addr; + size_t max_size; + + /* pthread_getattr_np() will return bogus values for the main thread with + * musl or with some old glibc versions */ + ZEND_ASSERT(!zend_call_stack_is_main_thread()); + + error = pthread_getattr_np(pthread_self(), &attr); + if (error) { + return false; + } + + error = pthread_attr_getstack(&attr, &addr, &max_size); + if (error) { + return false; + } + +# if defined(__GLIBC__) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 8)) + { + size_t guard_size; + /* In glibc prior to 2.8, addr and size include the guard pages */ + error = pthread_attr_getguardsize(&attr, &guard_size); + if (error) { + return false; + } + + addr = (int8_t*)addr + guard_size; + max_size -= guard_size; + } +# endif /* glibc < 2.8 */ + + stack->base = (int8_t*)addr + max_size; + stack->max_size = max_size; + + return true; +} +# else /* HAVE_PTHREAD_GETATTR_NP */ +static bool zend_call_stack_get_linux_pthread(zend_call_stack *stack) +{ + return false; +} +# endif /* HAVE_PTHREAD_GETATTR_NP */ + +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 start, end, prev_end = 0; + size_t max_size; + bool found = false; + struct rlimit rlim; + int error; + + /* This method is relevant only for the main thread */ + ZEND_ASSERT(zend_call_stack_is_main_thread()); + + /* Scan the process memory mappings to find the one containing the stack. + * + * The end of the stack mapping is the base of the stack. The start is + * adjusted by the kernel as the stack grows. The maximum stack size is + * determined by RLIMIT_STACK and the previous mapping. + * + * + * ^ Higher addresses ^ + * : : + * : : + * Mapping end --> |-------------------| <-- Stack base (stack start) + * | | ^ + * | Stack Mapping | | Stack size + * | | v + * Mapping start --> |-------------------| <-- Current stack end + * (adjusted : : + * downwards as the . . + * stack grows) : : + * |-------------------| + * | Some Mapping | The previous mapping may prevent + * |-------------------| stack growth + * : : + * : : + * v Lower addresses v + */ + + f = fopen("/proc/self/maps", "r"); + if (!f) { + return false; + } + + while (fgets(buffer, sizeof(buffer), f) && sscanf(buffer, "%" SCNxPTR "-%" SCNxPTR, &start, &end) == 2) { + if (start <= addr_on_stack && end >= addr_on_stack) { + found = true; + break; + } + prev_end = end; + } + + fclose(f); + + if (!found) { + return false; + } + + error = getrlimit(RLIMIT_STACK, &rlim); + if (error || rlim.rlim_cur == RLIM_INFINITY) { + return false; + } + + max_size = rlim.rlim_cur; + + /* Previous mapping may prevent the stack from growing */ + if (end - max_size < prev_end) { + max_size = prev_end - end; + } + + stack->base = (void*)end; + stack->max_size = max_size; + + return true; +} + +static bool zend_call_stack_get_linux(zend_call_stack *stack) +{ + if (zend_call_stack_is_main_thread()) { + return zend_call_stack_get_linux_proc_maps(stack); + } + + return zend_call_stack_get_linux_pthread(stack); +} +#else /* __linux__ */ +static bool zend_call_stack_get_linux(zend_call_stack *stack) +{ + return false; +} +#endif /* __linux__ */ + +#ifdef __FreeBSD__ +static bool zend_call_stack_is_main_thread(void) +{ + int is_main = pthread_main_np(); + return is_main == -1 || is_main == 1; +} + +# if defined(HAVE_PTHREAD_ATTR_GET_NP) && defined(HAVE_PTHREAD_ATTR_GET_STACK) +static bool zend_call_stack_get_freebsd_pthread(zend_call_stack *stack) +{ + pthread_attr_t attr; + int error; + void *addr; + size_t max_size; + size_t guard_size; + + /* pthread will return bogus values for the main thread */ + ZEND_ASSERT(!zend_call_stack_is_main_thread()); + + pthread_attr_init(&attr); + + error = pthread_attr_get_np(pthread_self(), &attr); + if (error) { + goto fail; + } + + error = pthread_attr_getstack(&attr, &addr, &max_size); + if (error) { + goto fail; + } + + stack->base = (int8_t*)addr + max_size; + stack->max_size = max_size; + + pthread_attr_destroy(&attr); + return true; + +fail: + pthread_attr_destroy(&attr); + return false; +} +# else /* defined(HAVE_PTHREAD_ATTR_GET_NP) && defined(HAVE_PTHREAD_ATTR_GET_STACK) */ +static bool zend_call_stack_get_freebsd_pthread(zend_call_stack *stack) +{ + return false; +} +# endif /* defined(HAVE_PTHREAD_ATTR_GET_NP) && defined(HAVE_PTHREAD_ATTR_GET_STACK) */ + +static bool zend_call_stack_get_freebsd_sysctl(zend_call_stack *stack) +{ + void *stack_base; + int mib[2] = {CTL_KERN, KERN_USRSTACK}; + size_t len = sizeof(stack_base); + struct rlimit rlim; + + /* This method is relevant only for the main thread */ + ZEND_ASSERT(zend_call_stack_is_main_thread()); + + if (sysctl(mib, sizeof(mib)/sizeof(*mib), &stack_base, &len, NULL, 0) != 0) { + return false; + } + + if (getrlimit(RLIMIT_STACK, &rlim) != 0) { + return false; + } + + if (rlim.rlim_cur == RLIM_INFINITY) { + return false; + } + + size_t guard_size = getpagesize(); + + stack->base = stack_base; + stack->max_size = rlim.rlim_cur - guard_size; + + return true; +} + +static bool zend_call_stack_get_freebsd(zend_call_stack *stack) +{ + if (zend_call_stack_is_main_thread()) { + return zend_call_stack_get_freebsd_sysctl(stack); + } + + return zend_call_stack_get_freebsd_pthread(stack); +} +#else +static bool zend_call_stack_get_freebsd(zend_call_stack *stack) +{ + return false; +} +#endif /* __FreeBSD__ */ + +#ifdef ZEND_WIN32 +static bool zend_call_stack_get_win32(zend_call_stack *stack) +{ + ULONG_PTR low_limit, high_limit; + ULONG size; + MEMORY_BASIC_INFORMATION guard_region = {0}, uncommitted_region = {0}; + size_t result_size, page_size; + + /* The stack consists of three regions: committed, guard, and uncommitted. + * Memory is committed when the guard region is accessed. If only one page + * is left in the uncommitted region, a stack overflow error is raised + * instead. + * + * The total useable stack size is the size of the committed and uncommitted + * regions less one page. + * + * http://blogs.msdn.com/b/satyem/archive/2012/08/13/thread-s-stack-memory-management.aspx + * https://learn.microsoft.com/en-us/windows/win32/procthread/thread-stack-size + * + * ^ Higher addresses ^ + * : : + * : : + * high_limit --> |--------------------| + * ^ | | + * | | Committed region | + * | | | + * | |------------------- | <-- guard_region.BaseAddress + * reserved | | | + guard_region.RegionSize + * size | | Guard region | + * | | | + * | |--------------------| <-- guard_region.BaseAddress, + * | | | uncommitted_region.BaseAddress + * | | Uncommitted region | + uncommitted_region.RegionSize + * v | | + * low_limit --> |------------------- | <-- uncommitted_region.BaseAddress + * : : + * : : + * v Lower addresses v + */ + + GetCurrentThreadStackLimits(&low_limit, &high_limit); + + result_size = VirtualQuery((void*)low_limit, + &uncommitted_region, sizeof(uncommitted_region)); + ZEND_ASSERT(result_size >= sizeof(uncommitted_region)); + + result_size = VirtualQuery((int8_t*)uncommitted_region.BaseAddress + uncommitted_region.RegionSize, + &guard_region, sizeof(guard_region)); + ZEND_ASSERT(result_size >= sizeof(uncommitted_region)); + + stack->base = (void*)high_limit; + stack->max_size = (uintptr_t)high_limit - (uintptr_t)low_limit; + + ZEND_ASSERT(stack->max_size > guard_region.RegionSize); + stack->max_size -= guard_region.RegionSize; + + /* The uncommitted region does not shrink below 1 page */ + page_size = zend_get_page_size(); + ZEND_ASSERT(stack->max_size > page_size); + stack->max_size -= page_size; + + return true; +} +#else /* ZEND_WIN32 */ +static bool zend_call_stack_get_win32(zend_call_stack *stack) +{ + return false; +} +#endif /* ZEND_WIN32 */ + +#if defined(__APPLE__) && defined(HAVE_PTHREAD_GET_STACKADDR_NP) +static bool zend_call_stack_get_macos(zend_call_stack *stack) +{ + void *base = pthread_get_stackaddr_np(pthread_self()); + size_t max_size; + + if (pthread_main_np()) { + /* pthread_get_stacksize_np() returns a too low value for the main + * thread in OSX 10.9, 10.10: + * https://mail.openjdk.org/pipermail/hotspot-dev/2013-October/011353.html + * https://github.com/rust-lang/rust/issues/43347 + */ + + /* Stack size is 8MiB by default for main threads + * https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html */ + max_size = 8 * 1024 * 1024; + } else { + max_size = pthread_get_stacksize_np(pthread_self()); + } + + stack->base = base; + stack->max_size = max_size; + + return true; +} +#else /* defined(__APPLE__) && defined(HAVE_PTHREAD_GET_STACKADDR_NP) */ +static bool zend_call_stack_get_macos(zend_call_stack *stack) +{ + return false; +} +#endif /* defined(__APPLE__) && defined(HAVE_PTHREAD_GET_STACKADDR_NP) */ + +/** Get the stack information for the calling thread */ +ZEND_API bool zend_call_stack_get(zend_call_stack *stack) +{ + if (zend_call_stack_get_linux(stack)) { + return true; + } + + if (zend_call_stack_get_freebsd(stack)) { + return true; + } + + if (zend_call_stack_get_win32(stack)) { + return true; + } + + if (zend_call_stack_get_macos(stack)) { + return true; + } + + return false; +} + +#endif /* ZEND_CHECK_STACK_LIMIT */ diff --git a/Zend/zend_call_stack.h b/Zend/zend_call_stack.h new file mode 100644 index 0000000000000..d73c333eeeae2 --- /dev/null +++ b/Zend/zend_call_stack.h @@ -0,0 +1,91 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Arnaud Le Blanc | + +----------------------------------------------------------------------+ +*/ + +#ifndef ZEND_CALL_STACK_H +#define ZEND_CALL_STACK_H + +#include "zend.h" +#include "zend_portability.h" +#ifdef __APPLE__ +# include +#endif + +#ifdef ZEND_CHECK_STACK_LIMIT + +typedef struct _zend_call_stack { + void *base; + size_t max_size; +} zend_call_stack; + +ZEND_API void zend_call_stack_init(void); + +ZEND_API bool zend_call_stack_get(zend_call_stack *stack); + +/** Returns an approximation of the current stack position */ +static zend_always_inline void *zend_call_stack_position(void) { +#ifdef ZEND_WIN32 + return _AddressOfReturnAddress(); +#elif HAVE_BUILTIN_FRAME_ADDRESS + return __builtin_frame_address(0); +#else + void *a; + void *pos = (void*)&a; + return pos; +#endif +} + +static zend_always_inline bool zend_call_stack_overflowed(void *stack_limit) { + return (uintptr_t) zend_call_stack_position() <= (uintptr_t) stack_limit; +} + +static inline void* zend_call_stack_limit(void *base, size_t size, size_t reserved_size) +{ + if (UNEXPECTED(size > (uintptr_t)base)) { + return (void*)0; + } + + base = (int8_t*)base - size; + + if (UNEXPECTED(UINTPTR_MAX - (uintptr_t)base < reserved_size)) { + return (void*)UINTPTR_MAX; + } + + return (int8_t*)base + reserved_size; +} + +static inline size_t zend_call_stack_default_size(void) +{ +#ifdef __linux__ + return 8 * 1024 * 1024; +#endif +#ifdef __FreeBSD__ + return 8 * 1024 * 1024; +#endif +#ifdef __APPLE__ + // https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html + if (pthread_main_np()) { + return 8 * 1024 * 1024; + } + return 512 * 1024; +#endif + + return 2 * 1024 * 1024; +} + +#endif /* ZEND_CHECK_STACK_LIMIT */ +#endif /* ZEND_CALL_STACK_H */ diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index fc5216b797082..4cb9b9c85305b 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -34,6 +34,7 @@ #include "zend_vm.h" #include "zend_enum.h" #include "zend_observer.h" +#include "zend_call_stack.h" #define SET_NODE(target, src) do { \ target ## _type = (src)->op_type; \ @@ -10425,6 +10426,14 @@ static void zend_compile_expr_inner(znode *result, zend_ast *ast) /* {{{ */ static void zend_compile_expr(znode *result, zend_ast *ast) { +#ifdef ZEND_CHECK_STACK_LIMIT + if (UNEXPECTED(zend_call_stack_overflowed(EG(stack_limit)))) { + zend_error_noreturn(E_COMPILE_ERROR, + "Maximum call stack size of %zu bytes reached during compilation. Try splitting expression", + (size_t) ((uintptr_t) EG(stack_base) - (uintptr_t) EG(stack_limit))); + } +#endif /* ZEND_CHECK_STACK_LIMIT */ + uint32_t checkpoint = zend_short_circuiting_checkpoint(); zend_compile_expr_inner(result, ast); zend_short_circuiting_commit(checkpoint, result, ast); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index fc54a8e0262e1..b0f87eccb11c9 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -42,6 +42,7 @@ #include "zend_smart_str.h" #include "zend_observer.h" #include "zend_system_id.h" +#include "zend_call_stack.h" #include "Optimizer/zend_func_info.h" /* Virtual current working directory support */ @@ -2228,6 +2229,14 @@ static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_use_new_element_for_s zend_throw_error(NULL, "[] operator not supported for strings"); } +#ifdef ZEND_CHECK_STACK_LIMIT +static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_call_stack_size_error(void) +{ + zend_throw_error(NULL, "Maximum call stack size of %zu bytes reached. Infinite recursion?", + (size_t) ((uintptr_t) EG(stack_base) - (uintptr_t) EG(stack_limit))); +} +#endif /* ZEND_CHECK_STACK_LIMIT */ + static ZEND_COLD void zend_binary_assign_op_dim_slow(zval *container, zval *dim OPLINE_DC EXECUTE_DATA_DC) { if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 3c29ac7dc6090..17c3caae21432 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -37,6 +37,7 @@ #include "zend_weakrefs.h" #include "zend_inheritance.h" #include "zend_observer.h" +#include "zend_call_stack.h" #ifdef HAVE_SYS_TIME_H #include #endif diff --git a/Zend/zend_fibers.c b/Zend/zend_fibers.c index f5246e74251dd..f6065561793da 100644 --- a/Zend/zend_fibers.c +++ b/Zend/zend_fibers.c @@ -108,6 +108,10 @@ typedef struct _zend_fiber_vm_state { uint32_t jit_trace_num; JMP_BUF *bailout; zend_fiber *active_fiber; +#ifdef ZEND_CHECK_STACK_LIMIT + void *stack_base; + void *stack_limit; +#endif } zend_fiber_vm_state; static zend_always_inline void zend_fiber_capture_vm_state(zend_fiber_vm_state *state) @@ -121,6 +125,10 @@ static zend_always_inline void zend_fiber_capture_vm_state(zend_fiber_vm_state * state->jit_trace_num = EG(jit_trace_num); state->bailout = EG(bailout); state->active_fiber = EG(active_fiber); +#ifdef ZEND_CHECK_STACK_LIMIT + state->stack_base = EG(stack_base); + state->stack_limit = EG(stack_limit); +#endif } static zend_always_inline void zend_fiber_restore_vm_state(zend_fiber_vm_state *state) @@ -134,6 +142,10 @@ static zend_always_inline void zend_fiber_restore_vm_state(zend_fiber_vm_state * EG(jit_trace_num) = state->jit_trace_num; EG(bailout) = state->bailout; EG(active_fiber) = state->active_fiber; +#ifdef ZEND_CHECK_STACK_LIMIT + EG(stack_base) = state->stack_base; + EG(stack_limit) = state->stack_limit; +#endif } #ifdef ZEND_FIBER_UCONTEXT @@ -294,6 +306,31 @@ static void zend_fiber_stack_free(zend_fiber_stack *stack) efree(stack); } + +#ifdef ZEND_CHECK_STACK_LIMIT +ZEND_API void* zend_fiber_stack_limit(zend_fiber_stack *stack) +{ + zend_ulong reserve = EG(reserved_stack_size); + +#ifdef __APPLE__ + /* On Apple Clang, the stack probing function ___chkstk_darwin incorrectly + * probes a location that is twice the entered function's stack usage away + * from the stack pointer, when using an alternative stack. + * https://openradar.appspot.com/radar?id=5497722702397440 + */ + reserve = reserve * 2; +#endif + + /* stack->pointer is the end of the stack */ + return (int8_t*)stack->pointer + reserve; +} + +ZEND_API void* zend_fiber_stack_base(zend_fiber_stack *stack) +{ + return (void*)((uintptr_t)stack->pointer + stack->size); +} +#endif + #ifdef ZEND_FIBER_UCONTEXT static ZEND_NORETURN void zend_fiber_trampoline(void) #else @@ -535,6 +572,11 @@ static ZEND_STACK_ALIGNED void zend_fiber_execute(zend_fiber_transfer *transfer) EG(jit_trace_num) = 0; EG(error_reporting) = error_reporting; +#ifdef ZEND_CHECK_STACK_LIMIT + EG(stack_base) = zend_fiber_stack_base(fiber->context.stack); + EG(stack_limit) = zend_fiber_stack_limit(fiber->context.stack); +#endif + fiber->fci.retval = &fiber->result; zend_call_function(&fiber->fci, &fiber->fci_cache); diff --git a/Zend/zend_fibers.h b/Zend/zend_fibers.h index 2673e7814b093..5faa788f4ef68 100644 --- a/Zend/zend_fibers.h +++ b/Zend/zend_fibers.h @@ -136,6 +136,10 @@ struct _zend_fiber { ZEND_API bool zend_fiber_init_context(zend_fiber_context *context, void *kind, zend_fiber_coroutine coroutine, size_t stack_size); ZEND_API void zend_fiber_destroy_context(zend_fiber_context *context); ZEND_API void zend_fiber_switch_context(zend_fiber_transfer *transfer); +#ifdef ZEND_CHECK_STACK_LIMIT +ZEND_API void* zend_fiber_stack_limit(zend_fiber_stack *stack); +ZEND_API void* zend_fiber_stack_base(zend_fiber_stack *stack); +#endif /* ZEND_CHECK_STACK_LIMIT */ ZEND_API void zend_fiber_switch_block(void); ZEND_API void zend_fiber_switch_unblock(void); diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 17469fab0c11e..66ba9a6a32706 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -37,6 +37,7 @@ #include "zend_multibyte.h" #include "zend_multiply.h" #include "zend_arena.h" +#include "zend_call_stack.h" /* Define ZTS if you want a thread-safe Zend */ /*#undef ZTS*/ @@ -54,6 +55,10 @@ END_EXTERN_C() #define SYMTABLE_CACHE_SIZE 32 +#ifdef ZEND_CHECK_STACK_LIMIT +# define ZEND_MAX_ALLOWED_STACK_SIZE_UNCHECKED -1 +# define ZEND_MAX_ALLOWED_STACK_SIZE_DETECT 0 +#endif #include "zend_compile.h" @@ -193,6 +198,8 @@ struct _zend_executor_globals { zend_atomic_bool vm_interrupt; zend_atomic_bool timed_out; zend_long hard_timeout; + void *stack_base; + void *stack_limit; #ifdef ZEND_WIN32 OSVERSIONINFOEX windows_version_info; @@ -271,6 +278,12 @@ struct _zend_executor_globals { zend_string *filename_override; zend_long lineno_override; +#ifdef ZEND_CHECK_STACK_LIMIT + zend_call_stack call_stack; + zend_long max_allowed_stack_size; + zend_ulong reserved_stack_size; +#endif + void *reserved[ZEND_MAX_RESERVED_RESOURCES]; }; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 202bc3ad0097e..ff2cae79e414e 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -7928,6 +7928,12 @@ ZEND_VM_HELPER(zend_dispatch_try_catch_finally_helper, ANY, ANY, uint32_t try_ca ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) { const zend_op *throw_op = EG(opline_before_exception); + + /* Exception was thrown before executing any op */ + if (UNEXPECTED(!throw_op)) { + ZEND_VM_DISPATCH_TO_HELPER(zend_dispatch_try_catch_finally_helper, try_catch_offset, -1, 0, 0); + } + uint32_t throw_op_num = throw_op - EX(func)->op_array.opcodes; int i, current_try_catch_offset = -1; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 7d1545ba0fce1..8008cfd8b2794 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3181,6 +3181,12 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_dispatch_try static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { const zend_op *throw_op = EG(opline_before_exception); + + /* Exception was thrown before executing any op */ + if (UNEXPECTED(!throw_op)) { + ZEND_VM_TAIL_CALL(zend_dispatch_try_catch_finally_helper_SPEC(-1, 0 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + } + uint32_t throw_op_num = throw_op - EX(func)->op_array.opcodes; int i, current_try_catch_offset = -1; @@ -55774,6 +55780,16 @@ ZEND_API void execute_ex(zend_execute_data *ex) LOAD_OPLINE(); ZEND_VM_LOOP_INTERRUPT_CHECK(); +#ifdef ZEND_CHECK_STACK_LIMIT + if (UNEXPECTED(zend_call_stack_overflowed(EG(stack_limit)))) { + zend_call_stack_size_error(); + /* No opline was executed before exception */ + EG(opline_before_exception) = NULL; + LOAD_OPLINE(); + /* Fall through to handle exception below. */ + } +#endif /* ZEND_CHECK_STACK_LIMIT */ + while (1) { #if !defined(ZEND_VM_FP_GLOBAL_REG) || !defined(ZEND_VM_IP_GLOBAL_REG) int ret; diff --git a/Zend/zend_vm_execute.skl b/Zend/zend_vm_execute.skl index 582ec490e2d77..a131eead57205 100644 --- a/Zend/zend_vm_execute.skl +++ b/Zend/zend_vm_execute.skl @@ -16,6 +16,16 @@ ZEND_API void {%EXECUTOR_NAME%}_ex(zend_execute_data *ex) LOAD_OPLINE(); ZEND_VM_LOOP_INTERRUPT_CHECK(); +#ifdef ZEND_CHECK_STACK_LIMIT + if (UNEXPECTED(zend_call_stack_overflowed(EG(stack_limit)))) { + zend_call_stack_size_error(); + /* No opline was executed before exception */ + EG(opline_before_exception) = NULL; + LOAD_OPLINE(); + /* Fall through to handle exception below. */ + } +#endif /* ZEND_CHECK_STACK_LIMIT */ + while (1) { {%ZEND_VM_CONTINUE_LABEL%} {%ZEND_VM_DISPATCH%} { diff --git a/build/php.m4 b/build/php.m4 index e4bef9d9f2d14..34652da7d8d29 100644 --- a/build/php.m4 +++ b/build/php.m4 @@ -2733,6 +2733,26 @@ AC_DEFUN([PHP_CHECK_BUILTIN_CPU_SUPPORTS], [ [$have_builtin_cpu_supports], [Whether the compiler supports __builtin_cpu_supports]) ]) +dnl +dnl PHP_CHECK_BUILTIN_FRAME_ADDRESS +dnl +AC_DEFUN([PHP_CHECK_BUILTIN_FRAME_ADDRESS], [ + AC_MSG_CHECKING([for __builtin_frame_address]) + + AC_LINK_IFELSE([AC_LANG_PROGRAM([], [[ + return __builtin_frame_address(0) != (void*)0; + ]])], [ + have_builtin_frame_address=1 + AC_MSG_RESULT([yes]) + ], [ + have_builtin_frame_address=0 + AC_MSG_RESULT([no]) + ]) + + AC_DEFINE_UNQUOTED([PHP_HAVE_BUILTIN_FRAME_ADDRESS], + [$have_builtin_frame_address], [Whether the compiler supports __builtin_frame_address]) +]) + dnl dnl PHP_PATCH_CONFIG_HEADERS([FILE]) dnl diff --git a/configure.ac b/configure.ac index a64ca2d042f72..690b6ad0a26e4 100644 --- a/configure.ac +++ b/configure.ac @@ -510,6 +510,8 @@ dnl Check __builtin_cpu_init PHP_CHECK_BUILTIN_CPU_INIT dnl Check __builtin_cpu_supports PHP_CHECK_BUILTIN_CPU_SUPPORTS +dnl Check __builtin_frame_address +PHP_CHECK_BUILTIN_FRAME_ADDRESS dnl Check prctl PHP_CHECK_PRCTL dnl Check procctl @@ -1701,7 +1703,7 @@ PHP_ADD_SOURCES_X(/main, internal_functions_cli.c, -DZEND_ENABLE_STATIC_TSRMLS_C PHP_ADD_SOURCES(Zend, \ zend_language_parser.c zend_language_scanner.c \ zend_ini_parser.c zend_ini_scanner.c \ - zend_alloc.c zend_compile.c zend_constants.c zend_dtrace.c \ + zend_alloc.c zend_call_stack.c zend_compile.c zend_constants.c zend_dtrace.c \ zend_execute_API.c zend_highlight.c zend_llist.c \ zend_vm_opcodes.c zend_opcode.c zend_operators.c zend_ptr_stack.c zend_stack.c \ zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c index 6d9b7ec8ffdcd..b2539f5c3f429 100644 --- a/ext/opcache/jit/zend_jit_helpers.c +++ b/ext/opcache/jit/zend_jit_helpers.c @@ -21,7 +21,7 @@ static ZEND_COLD void undef_result_after_exception(void) { const zend_op *opline = EG(opline_before_exception); ZEND_ASSERT(EG(exception)); - if (opline->result_type & (IS_VAR | IS_TMP_VAR)) { + if (opline && opline->result_type & (IS_VAR | IS_TMP_VAR)) { zend_execute_data *execute_data = EG(current_execute_data); ZVAL_UNDEF(EX_VAR(opline->result.var)); } @@ -785,7 +785,7 @@ static zval* ZEND_FASTCALL zend_jit_fetch_dim_rw_helper(zend_array *ht, zval *di if (UNEXPECTED(opline->opcode == ZEND_HANDLE_EXCEPTION)) { opline = EG(opline_before_exception); } - if (!zend_jit_undefined_op_helper_write(ht, opline->op2.var)) { + if (opline && !zend_jit_undefined_op_helper_write(ht, opline->op2.var)) { if (opline->result_type & (IS_VAR | IS_TMP_VAR)) { if (EG(exception)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); @@ -1003,7 +1003,8 @@ static zval* ZEND_FASTCALL zend_jit_fetch_dim_w_helper(zend_array *ht, zval *dim default: zend_jit_illegal_offset(); undef_result_after_exception(); - if ((EG(opline_before_exception)+1)->opcode == ZEND_OP_DATA + if (EG(opline_before_exception) + && (EG(opline_before_exception)+1)->opcode == ZEND_OP_DATA && ((EG(opline_before_exception)+1)->op1_type & (IS_VAR|IS_TMP_VAR))) { zend_execute_data *execute_data = EG(current_execute_data); diff --git a/ext/opcache/jit/zend_jit_vm_helpers.c b/ext/opcache/jit/zend_jit_vm_helpers.c index 5342731fc81b7..8e02fbbbfeac2 100644 --- a/ext/opcache/jit/zend_jit_vm_helpers.c +++ b/ext/opcache/jit/zend_jit_vm_helpers.c @@ -183,7 +183,7 @@ bool ZEND_FASTCALL zend_jit_deprecated_helper(OPLINE_D) zend_execute_data *execute_data = EG(current_execute_data); #endif const zend_op *opline = EG(opline_before_exception); - if (RETURN_VALUE_USED(opline)) { + if (opline && RETURN_VALUE_USED(opline)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); } diff --git a/ext/zend_test/fiber.c b/ext/zend_test/fiber.c index f67c0217d050f..428ecc0682dac 100644 --- a/ext/zend_test/fiber.c +++ b/ext/zend_test/fiber.c @@ -95,6 +95,10 @@ static ZEND_STACK_ALIGNED void zend_test_fiber_execute(zend_fiber_transfer *tran EG(current_execute_data) = execute_data; EG(jit_trace_num) = 0; +#ifdef ZEND_CHECK_STACK_LIMIT + EG(stack_base) = zend_fiber_stack_base(fiber->context.stack); + EG(stack_limit) = zend_fiber_stack_limit(fiber->context.stack); +#endif fiber->fci.retval = &retval; zend_call_function(&fiber->fci, &fiber->fci_cache); diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index afba5a3614efd..9ec9455023319 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -30,6 +30,7 @@ #include "zend_weakrefs.h" #include "Zend/Optimizer/zend_optimizer.h" #include "test_arginfo.h" +#include "zend_call_stack.h" ZEND_DECLARE_MODULE_GLOBALS(zend_test) @@ -456,6 +457,65 @@ static ZEND_FUNCTION(zend_test_parameter_with_attribute) RETURN_LONG(1); } +#ifdef ZEND_CHECK_STACK_LIMIT +static ZEND_FUNCTION(zend_test_zend_call_stack_get) +{ + zend_call_stack stack; + + ZEND_PARSE_PARAMETERS_NONE(); + + if (zend_call_stack_get(&stack)) { + zend_string *str; + + array_init(return_value); + + str = strpprintf(0, "%p", stack.base); + add_assoc_str(return_value, "base", str); + + str = strpprintf(0, "0x%zx", stack.max_size); + add_assoc_str(return_value, "max_size", str); + + str = strpprintf(0, "%p", zend_call_stack_position()); + add_assoc_str(return_value, "position", str); + + str = strpprintf(0, "%p", EG(stack_limit)); + add_assoc_str(return_value, "EG(stack_limit)", str); + + return; + } + + RETURN_NULL(); +} + +zend_long (*volatile zend_call_stack_use_all_fun)(void *limit); + +static zend_long zend_call_stack_use_all(void *limit) +{ + if (zend_call_stack_overflowed(limit)) { + return 1; + } + + return 1 + zend_call_stack_use_all_fun(limit); +} + +static ZEND_FUNCTION(zend_test_zend_call_stack_use_all) +{ + zend_call_stack stack; + + ZEND_PARSE_PARAMETERS_NONE(); + + if (!zend_call_stack_get(&stack)) { + return; + } + + zend_call_stack_use_all_fun = zend_call_stack_use_all; + + void *limit = zend_call_stack_limit(stack.base, stack.max_size, 4096); + + RETURN_LONG(zend_call_stack_use_all(limit)); +} +#endif /* ZEND_CHECK_STACK_LIMIT */ + static zend_object *zend_test_class_new(zend_class_entry *class_type) { zend_object *obj = zend_objects_new(class_type); diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index a0a042a8297df..95b26fabd0093 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -161,6 +161,11 @@ function zend_test_zend_ini_parse_quantity(string $str): int {} function zend_test_zend_ini_parse_uquantity(string $str): int {} function zend_test_zend_ini_str(): string {} + +#ifdef ZEND_CHECK_STACK_LIMIT + function zend_test_zend_call_stack_get(): ?array {} + function zend_test_zend_call_stack_use_all(): int {} +#endif } namespace ZendTestNS { diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index 14e9c29bd103d..52fd88d008c93 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 786b35a1fbff38215431d5ae46a5816c70defce5 */ + * Stub hash: 5c7af89178bc4ea0f49fbf516d81f4fdaebece22 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -97,6 +97,16 @@ ZEND_END_ARG_INFO() #define arginfo_zend_test_zend_ini_str arginfo_zend_get_current_func_name +#if defined(ZEND_CHECK_STACK_LIMIT) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_zend_call_stack_get, 0, 0, IS_ARRAY, 1) +ZEND_END_ARG_INFO() +#endif + +#if defined(ZEND_CHECK_STACK_LIMIT) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_zend_call_stack_use_all, 0, 0, IS_LONG, 0) +ZEND_END_ARG_INFO() +#endif + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ZendTestNS2_namespaced_func, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() @@ -185,6 +195,12 @@ static ZEND_FUNCTION(zend_call_method); static ZEND_FUNCTION(zend_test_zend_ini_parse_quantity); static ZEND_FUNCTION(zend_test_zend_ini_parse_uquantity); static ZEND_FUNCTION(zend_test_zend_ini_str); +#if defined(ZEND_CHECK_STACK_LIMIT) +static ZEND_FUNCTION(zend_test_zend_call_stack_get); +#endif +#if defined(ZEND_CHECK_STACK_LIMIT) +static ZEND_FUNCTION(zend_test_zend_call_stack_use_all); +#endif static ZEND_FUNCTION(ZendTestNS2_namespaced_func); static ZEND_FUNCTION(ZendTestNS2_namespaced_deprecated_func); static ZEND_FUNCTION(ZendTestNS2_ZendSubNS_namespaced_func); @@ -235,6 +251,12 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(zend_test_zend_ini_parse_quantity, arginfo_zend_test_zend_ini_parse_quantity) ZEND_FE(zend_test_zend_ini_parse_uquantity, arginfo_zend_test_zend_ini_parse_uquantity) ZEND_FE(zend_test_zend_ini_str, arginfo_zend_test_zend_ini_str) +#if defined(ZEND_CHECK_STACK_LIMIT) + ZEND_FE(zend_test_zend_call_stack_get, arginfo_zend_test_zend_call_stack_get) +#endif +#if defined(ZEND_CHECK_STACK_LIMIT) + ZEND_FE(zend_test_zend_call_stack_use_all, arginfo_zend_test_zend_call_stack_use_all) +#endif ZEND_NS_FALIAS("ZendTestNS2", namespaced_func, ZendTestNS2_namespaced_func, arginfo_ZendTestNS2_namespaced_func) ZEND_NS_DEP_FALIAS("ZendTestNS2", namespaced_deprecated_func, ZendTestNS2_namespaced_deprecated_func, arginfo_ZendTestNS2_namespaced_deprecated_func) ZEND_NS_FALIAS("ZendTestNS2", namespaced_aliased_func, zend_test_void_return, arginfo_ZendTestNS2_namespaced_aliased_func) diff --git a/sapi/phpdbg/phpdbg_utils.c b/sapi/phpdbg/phpdbg_utils.c index 344b9c73e476d..b381f574fc10a 100644 --- a/sapi/phpdbg/phpdbg_utils.c +++ b/sapi/phpdbg/phpdbg_utils.c @@ -611,7 +611,7 @@ PHPDBG_API bool phpdbg_check_caught_ex(zend_execute_data *execute_data, zend_obj uint32_t op_num, i; zend_op_array *op_array = &execute_data->func->op_array; - if (execute_data->opline >= EG(exception_op) && execute_data->opline < EG(exception_op) + 3) { + if (execute_data->opline >= EG(exception_op) && execute_data->opline < EG(exception_op) + 3 && EG(opline_before_exception)) { op = EG(opline_before_exception); } else { op = execute_data->opline; diff --git a/win32/build/config.w32 b/win32/build/config.w32 index 0b1736c8ab70d..20fcf2409922f 100644 --- a/win32/build/config.w32 +++ b/win32/build/config.w32 @@ -228,8 +228,8 @@ STDOUT.WriteLine("Build dir: " + get_define('BUILD_DIR')); STDOUT.WriteLine("PHP Core: " + get_define('PHPDLL') + " and " + get_define('PHPLIB')); ADD_SOURCES("Zend", "zend_language_parser.c zend_language_scanner.c \ - zend_ini_parser.c zend_ini_scanner.c zend_alloc.c zend_compile.c \ - zend_constants.c zend_exceptions.c \ + zend_ini_parser.c zend_ini_scanner.c zend_alloc.c zend_call_stack.c \ + zend_compile.c zend_constants.c zend_exceptions.c \ zend_execute_API.c zend_highlight.c \ zend_llist.c zend_vm_opcodes.c zend_opcode.c zend_operators.c zend_ptr_stack.c \ zend_stack.c zend_variables.c zend.c zend_API.c zend_extensions.c \ @@ -303,6 +303,9 @@ if (VS_TOOLSET && VCVERS >= 1914) { AC_DEFINE('HAVE_STRNLEN', 1); +AC_DEFINE('ZEND_STACK_GROWS_DOWNWARDS', 1) +AC_DEFINE('ZEND_CHECK_STACK_LIMIT', 1) + ADD_SOURCES("main/streams", "streams.c cast.c memory.c filter.c plain_wrapper.c \ userspace.c transports.c xp_socket.c mmap.c glob_wrapper.c"); ADD_FLAG("CFLAGS_BD_MAIN_STREAMS", "/D ZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); diff --git a/win32/build/config.w32.h.in b/win32/build/config.w32.h.in index 7686fb83a4a32..b513776eef70d 100644 --- a/win32/build/config.w32.h.in +++ b/win32/build/config.w32.h.in @@ -5,7 +5,7 @@ /* Define the minimum supported version */ #undef _WIN32_WINNT #undef NTDDI_VERSION -#define _WIN32_WINNT 0x0601 +#define _WIN32_WINNT 0x0602 #define NTDDI_VERSION 0x06010000 /* Default PHP / PEAR directories */