From cdfd9601504b620610b2b8c5c6cc090706fb33dd Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Tue, 10 Dec 2024 13:43:29 +0100 Subject: [PATCH] Fix ZEND_MATCH_ERROR misoptimization op1 of ZEND_MATCH_ERROR, which refers to the match expression, is not freed by MATCH_ERROR itself. Instead, it is freed by ZEND_HANDLE_EXCEPTION. For normal control flow, a FREE is placed at the end of the match expression. Since FREE may appear after MATCH_ERROR in the opcode sequence, we need to correctly handle op1 of MATCH_ERROR as alive. Fixes GH-17106 Closes GH-17108 --- NEWS | 3 +++ Zend/Optimizer/zend_optimizer.c | 2 ++ Zend/zend_opcode.c | 1 + ext/opcache/tests/gh17106.phpt | 21 +++++++++++++++++++++ 4 files changed, 27 insertions(+) create mode 100644 ext/opcache/tests/gh17106.phpt diff --git a/NEWS b/NEWS index 209c5dfc1ef..caad15a445e 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.3.16 +- Core: + . Fixed bug GH-17106 (ZEND_MATCH_ERROR misoptimization). (ilutov) + - DBA: . Skip test if inifile is disabled. (orlitzky) diff --git a/Zend/Optimizer/zend_optimizer.c b/Zend/Optimizer/zend_optimizer.c index d8ff9e5f0b8..857968e621b 100644 --- a/Zend/Optimizer/zend_optimizer.c +++ b/Zend/Optimizer/zend_optimizer.c @@ -640,6 +640,7 @@ bool zend_optimizer_replace_by_const(zend_op_array *op_array, case ZEND_SWITCH_LONG: case ZEND_SWITCH_STRING: case ZEND_MATCH: + case ZEND_MATCH_ERROR: case ZEND_JMP_NULL: { zend_op *end = op_array->opcodes + op_array->last; while (opline < end) { @@ -652,6 +653,7 @@ bool zend_optimizer_replace_by_const(zend_op_array *op_array, && opline->opcode != ZEND_SWITCH_LONG && opline->opcode != ZEND_SWITCH_STRING && opline->opcode != ZEND_MATCH + && opline->opcode != ZEND_MATCH_ERROR && opline->opcode != ZEND_JMP_NULL && (opline->opcode != ZEND_FREE || opline->extended_value != ZEND_FREE_ON_RETURN); diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 93195a1be4c..55bf81376d9 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -877,6 +877,7 @@ static bool keeps_op1_alive(zend_op *opline) { || opline->opcode == ZEND_SWITCH_LONG || opline->opcode == ZEND_SWITCH_STRING || opline->opcode == ZEND_MATCH + || opline->opcode == ZEND_MATCH_ERROR || opline->opcode == ZEND_FETCH_LIST_R || opline->opcode == ZEND_FETCH_LIST_W || opline->opcode == ZEND_COPY_TMP) { diff --git a/ext/opcache/tests/gh17106.phpt b/ext/opcache/tests/gh17106.phpt new file mode 100644 index 00000000000..5b56131b5a2 --- /dev/null +++ b/ext/opcache/tests/gh17106.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-17106: ZEND_MATCH_ERROR misoptimization +--EXTENSIONS-- +opcache +--INI-- +opcache.enable_cli=1 +opcache.optimization_level=-1 +--FILE-- + 2 }); +var_dump(match (X) { 2 => 2 }); + +?> +--EXPECT-- +int(7) +int(2) +int(2)