Skip to content

Commit ecf8e3e

Browse files
committed
Support stack limit in phpdbg SAPI
Add a stack limit check in zend_vm_call_opcode_handler for SAPIs that do not use execute_ex().
1 parent f35ad56 commit ecf8e3e

File tree

4 files changed

+94
-0
lines changed

4 files changed

+94
-0
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
--TEST--
2+
GH-16041 001: Stack overflow in phpdbg
3+
--SKIPIF--
4+
<?php
5+
if (ini_get('zend.max_allowed_stack_size') === false) {
6+
die('skip No stack limit support');
7+
}
8+
?>
9+
--INI--
10+
zend.max_allowed_stack_size=512K
11+
--PHPDBG--
12+
set pagination off
13+
run
14+
continue
15+
quit
16+
--FILE--
17+
<?php
18+
19+
class Canary {
20+
public function __destruct() {
21+
new Canary();
22+
}
23+
}
24+
25+
new Canary();
26+
27+
?>
28+
--EXPECTF--
29+
[Successful compilation of %sgh16041_001.php]
30+
prompt> prompt> [Uncaught Error in %s on line %d: Maximum call stack size of %d bytes%s
31+
>00005: new Canary();
32+
00006: }
33+
00007: }
34+
prompt> [Uncaught Error in %s on line %d]
35+
Error: Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion? in %s:%d
36+
Stack trace:
37+
#0 %s(%d): Canary->__destruct()
38+
%a
39+
prompt>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
GH-16041 002: Stack overflow in phpdbg
3+
--SKIPIF--
4+
<?php
5+
if (ini_get('zend.max_allowed_stack_size') === false) {
6+
die('skip No stack limit support');
7+
}
8+
?>
9+
--INI--
10+
zend.max_allowed_stack_size=512K
11+
--PHPDBG--
12+
set pagination off
13+
run
14+
quit
15+
--FILE--
16+
<?php
17+
18+
function map() {
19+
array_map('map', [1]);
20+
}
21+
22+
try {
23+
map();
24+
} catch (\Throwable $e) {
25+
printf("%s: %s\n", $e::class, $e->getMessage());
26+
}
27+
28+
?>
29+
--EXPECTF--
30+
[Successful compilation of %sgh16041_002.php]
31+
prompt> prompt> Error: Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?
32+
[Script ended normally]
33+
prompt>

Zend/zend_vm_execute.h

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Zend/zend_vm_gen.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2974,6 +2974,17 @@ function gen_vm($def, $skel) {
29742974
out($f, "#endif\n");
29752975
out($f, "\n");
29762976
out($f, "\tLOAD_OPLINE();\n");
2977+
out($f, "\n");
2978+
out($f, "\t#ifdef ZEND_CHECK_STACK_LIMIT\n");
2979+
out($f, "\t\tif (UNEXPECTED(zend_call_stack_overflowed(EG(stack_limit)))) {\n");
2980+
out($f, "\t\t\tzend_call_stack_size_error();\n");
2981+
out($f, "\t\t\t/* No opline was executed before exception */\n");
2982+
out($f, "\t\t\tEG(opline_before_exception) = NULL;\n");
2983+
out($f, "\t\t\tLOAD_OPLINE();\n");
2984+
out($f, "\t\t\t/* Fall through to handle exception below. */\n");
2985+
out($f, "\t\t}\n");
2986+
out($f, "\t#endif /* ZEND_CHECK_STACK_LIMIT */\n");
2987+
out($f, "\n");
29772988
out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n");
29782989
if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) {
29792990
out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n");

0 commit comments

Comments
 (0)