From a3b148e38d618b9d30e5ccfbc45d44cab2749396 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Mon, 3 Jun 2024 22:42:44 +0200 Subject: [PATCH] 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. --- NEWS | 2 ++ Zend/Optimizer/zend_cfg.c | 29 ++++++++++++++--------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/NEWS b/NEWS index c038a5bb11c..ee63bae14d6 100644 --- a/NEWS +++ b/NEWS @@ -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). diff --git a/Zend/Optimizer/zend_cfg.c b/Zend/Optimizer/zend_cfg.c index 4d3d62137b9..2a0fe369cfc 100644 --- a/Zend/Optimizer/zend_cfg.c +++ b/Zend/Optimizer/zend_cfg.c @@ -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; - } - - b = succ; - break; - } else { - /* Recursively check reachability */ - if (!(succ->flags & ZEND_BB_REACHABLE)) { - zend_mark_reachable(opcodes, cfg, succ); - } + /* Check reachability of successor */ + if (!(succ->flags & ZEND_BB_REACHABLE)) { + zend_worklist_push(&work, succ - cfg->blocks); } } } + + ZEND_WORKLIST_FREE_ALLOCA(&work, list_use_heap); } /* }}} */