Fix GH-14361: Deep recursion in zend_cfg.c causes segfault

Changes the CFG reachability algorithm to use iteration instead of
recursion.

Closes GH-14432.
This commit is contained in:
Niels Dossche 2024-06-03 22:42:44 +02:00
parent 2a02d35c2a
commit a3b148e38d
No known key found for this signature in database
GPG key ID: B8A8AD166DF0E2E5
2 changed files with 16 additions and 15 deletions

2
NEWS
View file

@ -121,6 +121,8 @@ PHP NEWS
64bit archs. (Arnaud)
. Fixed bug GH-13834 (Applying non-zero offset 36 to null pointer in
zend_jit.c). (nielsdos)
. Fixed bug GH-14361 (Deep recursion in zend_cfg.c causes segfault).
(nielsdos)
- OpenSSL:
. Fixed bug #80269 (OpenSSL sets Subject wrong with extraattribs parameter).

View file

@ -28,13 +28,20 @@ static void zend_mark_reachable(zend_op *opcodes, zend_cfg *cfg, zend_basic_bloc
{
zend_basic_block *blocks = cfg->blocks;
while (1) {
zend_worklist work;
ALLOCA_FLAG(list_use_heap)
ZEND_WORKLIST_ALLOCA(&work, cfg->blocks_count, list_use_heap);
zend_worklist_push(&work, b - cfg->blocks);
while (zend_worklist_len(&work)) {
int i;
b = cfg->blocks + zend_worklist_pop(&work);
b->flags |= ZEND_BB_REACHABLE;
if (b->successors_count == 0) {
b->flags |= ZEND_BB_EXIT;
return;
continue;
}
for (i = 0; i < b->successors_count; i++) {
@ -86,22 +93,14 @@ static void zend_mark_reachable(zend_op *opcodes, zend_cfg *cfg, zend_basic_bloc
succ->flags |= ZEND_BB_FOLLOW;
}
if (i == b->successors_count - 1) {
/* Tail call optimization */
if (succ->flags & ZEND_BB_REACHABLE) {
return;
/* Check reachability of successor */
if (!(succ->flags & ZEND_BB_REACHABLE)) {
zend_worklist_push(&work, succ - cfg->blocks);
}
}
}
b = succ;
break;
} else {
/* Recursively check reachability */
if (!(succ->flags & ZEND_BB_REACHABLE)) {
zend_mark_reachable(opcodes, cfg, succ);
}
}
}
}
ZEND_WORKLIST_FREE_ALLOCA(&work, list_use_heap);
}
/* }}} */