Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix GH-16041: Support stack limit in phpdbg SAPI #16055

Open
wants to merge 1 commit into
base: PHP-8.4
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions Zend/tests/stack_limit/gh16041_001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
--TEST--
GH-16041 001: Stack overflow in phpdbg
--SKIPIF--
<?php
if (ini_get('zend.max_allowed_stack_size') === false) {
die('skip No stack limit support');
}
?>
--INI--
zend.max_allowed_stack_size=512K
--PHPDBG--
set pagination off
run
continue
quit
--FILE--
<?php

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

new Canary();

?>
--EXPECTF--
[Successful compilation of %sgh16041_001.php]
prompt> prompt> [Uncaught Error in %s on line %d: Maximum call stack size of %d bytes%s
>00005: new Canary();
00006: }
00007: }
prompt> [Uncaught Error in %s on line %d]
Error: Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion? in %s:%d
Stack trace:
#0 %s(%d): Canary->__destruct()
%a
prompt>
33 changes: 33 additions & 0 deletions Zend/tests/stack_limit/gh16041_002.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
--TEST--
GH-16041 002: Stack overflow in phpdbg
--SKIPIF--
<?php
if (ini_get('zend.max_allowed_stack_size') === false) {
die('skip No stack limit support');
}
?>
--INI--
zend.max_allowed_stack_size=512K
--PHPDBG--
set pagination off
run
quit
--FILE--
<?php

function map() {
array_map('map', [1]);
}

try {
map();
} catch (\Throwable $e) {
printf("%s: %s\n", $e::class, $e->getMessage());
}

?>
--EXPECTF--
[Successful compilation of %sgh16041_002.php]
prompt> prompt> Error: Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?
[Script ended normally]
prompt>
2 changes: 1 addition & 1 deletion Zend/zend_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -2500,7 +2500,7 @@ 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)
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)) {
Expand Down
1 change: 1 addition & 0 deletions Zend/zend_execute.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_class_constant(const zend_
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_false_to_array_deprecated(void);
ZEND_COLD void ZEND_FASTCALL zend_param_must_be_ref(const zend_function *func, uint32_t arg_num);
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_use_resource_as_offset(const zval *dim);
zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_call_stack_size_error(void);

ZEND_API bool ZEND_FASTCALL zend_verify_ref_assignable_zval(zend_reference *ref, zval *zv, bool strict);

Expand Down
9 changes: 9 additions & 0 deletions sapi/phpdbg/phpdbg_prompt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1652,6 +1652,15 @@ void phpdbg_execute_ex(zend_execute_data *execute_data) /* {{{ */

PHPDBG_G(in_execution) = 1;

#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;
/* Fall through to handle exception below. */
}
#endif /* ZEND_CHECK_STACK_LIMIT */

while (1) {
zend_object *exception = EG(exception);

Expand Down
Loading