Skip to content

Commit

Permalink
Fix ZEND_MATCH_ERROR misoptimization
Browse files Browse the repository at this point in the history
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
  • Loading branch information
iluuu1994 committed Dec 12, 2024
1 parent 754aa77 commit cdfd960
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 0 deletions.
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
2 changes: 2 additions & 0 deletions Zend/Optimizer/zend_optimizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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);
Expand Down
1 change: 1 addition & 0 deletions Zend/zend_opcode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
21 changes: 21 additions & 0 deletions ext/opcache/tests/gh17106.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
--TEST--
GH-17106: ZEND_MATCH_ERROR misoptimization
--EXTENSIONS--
opcache
--INI--
opcache.enable_cli=1
opcache.optimization_level=-1
--FILE--
<?php

const X = 2;

var_dump(7 ?? match (X) {});
var_dump(null ?? match (X) { 2 => 2 });
var_dump(match (X) { 2 => 2 });

?>
--EXPECT--
int(7)
int(2)
int(2)

0 comments on commit cdfd960

Please sign in to comment.