Skip to content

Commit 7d38d0b

Browse files
committed
Add VM reentry limit
1 parent d8a1e3d commit 7d38d0b

9 files changed

+39
-0
lines changed

Zend/zend.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ ZEND_INI_BEGIN()
175175
STD_ZEND_INI_BOOLEAN("zend.signal_check", "0", ZEND_INI_SYSTEM, OnUpdateBool, check, zend_signal_globals_t, zend_signal_globals)
176176
#endif
177177
STD_ZEND_INI_BOOLEAN("zend.exception_ignore_args", "0", ZEND_INI_ALL, OnUpdateBool, exception_ignore_args, zend_executor_globals, executor_globals)
178+
STD_ZEND_INI_ENTRY("zend.vm_reentry_limit", "1000", ZEND_INI_ALL, OnUpdateLong, vm_reentry_limit, zend_executor_globals, executor_globals)
178179
ZEND_INI_END()
179180

180181
ZEND_API size_t zend_vspprintf(char **pbuf, size_t max_len, const char *format, va_list ap) /* {{{ */

Zend/zend_execute.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2009,6 +2009,13 @@ static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_use_new_element_for_s
20092009
zend_throw_error(NULL, "[] operator not supported for strings");
20102010
}
20112011

2012+
static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_vm_reentry_limit_error()
2013+
{
2014+
zend_throw_error(NULL,
2015+
"VM reentry limit of " ZEND_ULONG_FMT " reached. Infinite recursion?",
2016+
EG(vm_reentry_limit));
2017+
}
2018+
20122019
static ZEND_COLD void zend_binary_assign_op_dim_slow(zval *container, zval *dim OPLINE_DC EXECUTE_DATA_DC)
20132020
{
20142021
if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) {

Zend/zend_execute_API.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ void init_executor(void) /* {{{ */
174174

175175
EG(fake_scope) = NULL;
176176
EG(trampoline).common.function_name = NULL;
177+
EG(vm_reentry_count) = 0;
177178

178179
EG(ht_iterators_count) = sizeof(EG(ht_iterators_slots)) / sizeof(HashTableIterator);
179180
EG(ht_iterators_used) = 0;

Zend/zend_globals.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,8 @@ struct _zend_executor_globals {
237237
HashTable weakrefs;
238238

239239
zend_bool exception_ignore_args;
240+
zend_ulong vm_reentry_count;
241+
zend_ulong vm_reentry_limit;
240242

241243
void *reserved[ZEND_MAX_RESERVED_RESOURCES];
242244
};

Zend/zend_vm_execute.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51683,6 +51683,12 @@ ZEND_API void execute_ex(zend_execute_data *ex)
5168351683
LOAD_OPLINE();
5168451684
ZEND_VM_LOOP_INTERRUPT_CHECK();
5168551685

51686+
if (EG(vm_reentry_count)++ > EG(vm_reentry_limit)) {
51687+
zend_vm_reentry_limit_error();
51688+
LOAD_OPLINE();
51689+
/* Fall through to handle exception below. */
51690+
}
51691+
5168651692
while (1) {
5168751693
#if !defined(ZEND_VM_FP_GLOBAL_REG) || !defined(ZEND_VM_IP_GLOBAL_REG)
5168851694
int ret;
@@ -55921,6 +55927,7 @@ ZEND_API void execute_ex(zend_execute_data *ex)
5592155927
#ifdef ZEND_VM_IP_GLOBAL_REG
5592255928
opline = orig_opline;
5592355929
#endif
55930+
EG(vm_reentry_count)--;
5592455931
return;
5592555932
HYBRID_DEFAULT:
5592655933
VM_TRACE(ZEND_NULL)
@@ -55941,6 +55948,7 @@ ZEND_API void execute_ex(zend_execute_data *ex)
5594155948
# ifdef ZEND_VM_IP_GLOBAL_REG
5594255949
opline = orig_opline;
5594355950
# endif
55951+
EG(vm_reentry_count)--;
5594455952
return;
5594555953
}
5594655954
#endif

Zend/zend_vm_execute.skl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ ZEND_API void {%EXECUTOR_NAME%}_ex(zend_execute_data *ex)
1616
LOAD_OPLINE();
1717
ZEND_VM_LOOP_INTERRUPT_CHECK();
1818

19+
if (EG(vm_reentry_count)++ > EG(vm_reentry_limit)) {
20+
zend_vm_reentry_limit_error();
21+
LOAD_OPLINE();
22+
/* Fall through to handle exception below. */
23+
}
24+
1925
while (1) {
2026
{%ZEND_VM_CONTINUE_LABEL%}
2127
{%ZEND_VM_DISPATCH%} {

Zend/zend_vm_gen.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1753,6 +1753,7 @@ function gen_executor_code($f, $spec, $kind, $prolog, &$switch_labels = array())
17531753
out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n");
17541754
out($f,"\t\t\t\topline = orig_opline;\n");
17551755
out($f,"#endif\n");
1756+
out($f,"\t\t\t\tEG(vm_reentry_count)--;\n");
17561757
out($f,"\t\t\t\treturn;\n");
17571758
out($f,"\t\t\tHYBRID_DEFAULT:\n");
17581759
out($f,"\t\t\t\tVM_TRACE(ZEND_NULL)\n");
@@ -2158,6 +2159,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
21582159
"# ifdef ZEND_VM_IP_GLOBAL_REG\n" .
21592160
$m[1]."\topline = orig_opline;\n" .
21602161
"# endif\n".
2162+
$m[1]."\tEG(vm_reentry_count)--;\n".
21612163
$m[1]."\treturn;\n".
21622164
$m[1]."}\n".
21632165
"#endif\n");

php.ini-development

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,12 @@ zend.enable_gc = On
365365
; Default: Off
366366
zend.exception_ignore_args = Off
367367

368+
; Limit for recursion via VM reentry, used to prevent stack overflow.
369+
; This only affects recursion through magic method calls and similar mechanism.
370+
; Some profiling, debugging or APM extensions might make this limit apply to plain
371+
; recursion as well, in which case you may wish to raise it.
372+
;zend.vm_reentry_limit = 1000
373+
368374
;;;;;;;;;;;;;;;;;
369375
; Miscellaneous ;
370376
;;;;;;;;;;;;;;;;;

php.ini-production

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,12 @@ zend.enable_gc = On
367367
; of sensitive information in stack traces
368368
zend.exception_ignore_args = On
369369

370+
; Limit for recursion via VM reentry, used to prevent stack overflow.
371+
; This only affects recursion through magic method calls and similar mechanism.
372+
; Some profiling, debugging or APM extensions might make this limit apply to plain
373+
; recursion as well, in which case you may wish to raise it.
374+
;zend.vm_reentry_limit = 1000
375+
370376
;;;;;;;;;;;;;;;;;
371377
; Miscellaneous ;
372378
;;;;;;;;;;;;;;;;;

0 commit comments

Comments
 (0)