Skip to content

Commit 1c967df

Browse files
committed
Fix free of uninitialized memory in MATCH_ERROR
As suggested by Tyson Andre: #5371 (comment) Also fix line number of unhandled match error Closes GH-5841.
1 parent c0172aa commit 1c967df

File tree

3 files changed

+29
-27
lines changed

3 files changed

+29
-27
lines changed

Zend/tests/match/037.phpt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,13 @@ var_dump(match(3) {
5353

5454
?>
5555
--EXPECTF--
56-
string(%d) "UnhandledMatchError: Unhandled match value of type bool in %s037.php:5
56+
string(%d) "UnhandledMatchError: Unhandled match value of type bool in %s037.php:4
5757
Stack trace:
5858
#0 {main}"
59-
string(%d) "UnhandledMatchError: Unhandled match value of type int in %s037.php:13
59+
string(%d) "UnhandledMatchError: Unhandled match value of type int in %s037.php:12
6060
Stack trace:
6161
#0 {main}"
62-
string(%d) "UnhandledMatchError: Unhandled match value of type string in %s037.php:21
62+
string(%d) "UnhandledMatchError: Unhandled match value of type string in %s037.php:20
6363
Stack trace:
6464
#0 {main}"
6565
string(3) "foo"

Zend/zend_compile.c

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5297,6 +5297,24 @@ void zend_compile_match(znode *result, zend_ast *ast)
52975297
uint32_t cond_count = 0;
52985298
uint32_t *jmp_end_opnums = safe_emalloc(sizeof(uint32_t), arms->children, 0);
52995299

5300+
// The generated default arm is emitted first to avoid live range issues where the tmpvar
5301+
// for the arm result is freed even though it has not been initialized yet.
5302+
if (!has_default_arm) {
5303+
if (!uses_jumptable) {
5304+
zend_update_jump_target_to_next(opnum_default_jmp);
5305+
}
5306+
5307+
if (jumptable) {
5308+
zend_op *opline = &CG(active_op_array)->opcodes[opnum_match];
5309+
opline->extended_value = get_next_op_number();
5310+
}
5311+
5312+
zend_op *opline = zend_emit_op(NULL, ZEND_MATCH_ERROR, &expr_node, NULL);
5313+
if (opline->op1_type == IS_CONST) {
5314+
Z_TRY_ADDREF_P(CT_CONSTANT(opline->op1));
5315+
}
5316+
}
5317+
53005318
for (uint32_t i = 0; i < arms->children; ++i) {
53015319
zend_ast *arm_ast = arms->child[i];
53025320
zend_ast *body_ast = arm_ast->child[1];
@@ -5358,22 +5376,6 @@ void zend_compile_match(znode *result, zend_ast *ast)
53585376
ZVAL_NULL(&result->u.constant);
53595377
}
53605378

5361-
if (!has_default_arm) {
5362-
if (!uses_jumptable) {
5363-
zend_update_jump_target_to_next(opnum_default_jmp);
5364-
}
5365-
5366-
if (jumptable) {
5367-
zend_op *opline = &CG(active_op_array)->opcodes[opnum_match];
5368-
opline->extended_value = get_next_op_number();
5369-
}
5370-
5371-
zend_op *opline = zend_emit_op(NULL, ZEND_MATCH_ERROR, &expr_node, NULL);
5372-
if (opline->op1_type == IS_CONST) {
5373-
Z_TRY_ADDREF_P(CT_CONSTANT(opline->op1));
5374-
}
5375-
}
5376-
53775379
for (uint32_t i = 0; i < arms->children; ++i) {
53785380
zend_update_jump_target_to_next(jmp_end_opnums[i]);
53795381
}

ext/opcache/tests/match/001.phpt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,14 @@ test:
5252
; (after optimizer)
5353
; %s
5454
0000 CV0($char) = RECV 1
55-
0001 MATCH CV0($char) "a": 0002, "b": 0003, "c": 0003, "d": 0004, "e": 0005, "f": 0005, "g": 0006, "h": 0007, "i": 0007, default: 0008
56-
0002 RETURN string("a")
57-
0003 RETURN string("b, c")
58-
0004 RETURN string("d")
59-
0005 RETURN string("e, f")
60-
0006 RETURN string("g")
61-
0007 RETURN string("h, i")
62-
0008 MATCH_ERROR CV0($char)
55+
0001 MATCH CV0($char) "a": 0003, "b": 0004, "c": 0004, "d": 0005, "e": 0006, "f": 0006, "g": 0007, "h": 0008, "i": 0008, default: 0002
56+
0002 MATCH_ERROR CV0($char)
57+
0003 RETURN string("a")
58+
0004 RETURN string("b, c")
59+
0005 RETURN string("d")
60+
0006 RETURN string("e, f")
61+
0007 RETURN string("g")
62+
0008 RETURN string("h, i")
6363
string(1) "a"
6464
string(4) "b, c"
6565
string(4) "b, c"

0 commit comments

Comments
 (0)