Fix free of uninitialized memory in MATCH_ERROR

As suggested by Tyson Andre:
https://github.com/php/php-src/pull/5371#issuecomment-657081464

Also fix line number of unhandled match error

Closes GH-5841.
This commit is contained in:
Ilija Tovilo 2020-07-11 18:46:51 +02:00
parent c0172aa2bd
commit 1c967df5a0
No known key found for this signature in database
GPG Key ID: 3F123D0ADD448198
3 changed files with 29 additions and 27 deletions

View File

@ -53,13 +53,13 @@ var_dump(match(3) {
?>
--EXPECTF--
string(%d) "UnhandledMatchError: Unhandled match value of type bool in %s037.php:5
string(%d) "UnhandledMatchError: Unhandled match value of type bool in %s037.php:4
Stack trace:
#0 {main}"
string(%d) "UnhandledMatchError: Unhandled match value of type int in %s037.php:13
string(%d) "UnhandledMatchError: Unhandled match value of type int in %s037.php:12
Stack trace:
#0 {main}"
string(%d) "UnhandledMatchError: Unhandled match value of type string in %s037.php:21
string(%d) "UnhandledMatchError: Unhandled match value of type string in %s037.php:20
Stack trace:
#0 {main}"
string(3) "foo"

View File

@ -5297,6 +5297,24 @@ void zend_compile_match(znode *result, zend_ast *ast)
uint32_t cond_count = 0;
uint32_t *jmp_end_opnums = safe_emalloc(sizeof(uint32_t), arms->children, 0);
// The generated default arm is emitted first to avoid live range issues where the tmpvar
// for the arm result is freed even though it has not been initialized yet.
if (!has_default_arm) {
if (!uses_jumptable) {
zend_update_jump_target_to_next(opnum_default_jmp);
}
if (jumptable) {
zend_op *opline = &CG(active_op_array)->opcodes[opnum_match];
opline->extended_value = get_next_op_number();
}
zend_op *opline = zend_emit_op(NULL, ZEND_MATCH_ERROR, &expr_node, NULL);
if (opline->op1_type == IS_CONST) {
Z_TRY_ADDREF_P(CT_CONSTANT(opline->op1));
}
}
for (uint32_t i = 0; i < arms->children; ++i) {
zend_ast *arm_ast = arms->child[i];
zend_ast *body_ast = arm_ast->child[1];
@ -5358,22 +5376,6 @@ void zend_compile_match(znode *result, zend_ast *ast)
ZVAL_NULL(&result->u.constant);
}
if (!has_default_arm) {
if (!uses_jumptable) {
zend_update_jump_target_to_next(opnum_default_jmp);
}
if (jumptable) {
zend_op *opline = &CG(active_op_array)->opcodes[opnum_match];
opline->extended_value = get_next_op_number();
}
zend_op *opline = zend_emit_op(NULL, ZEND_MATCH_ERROR, &expr_node, NULL);
if (opline->op1_type == IS_CONST) {
Z_TRY_ADDREF_P(CT_CONSTANT(opline->op1));
}
}
for (uint32_t i = 0; i < arms->children; ++i) {
zend_update_jump_target_to_next(jmp_end_opnums[i]);
}

View File

@ -52,14 +52,14 @@ test:
; (after optimizer)
; %s
0000 CV0($char) = RECV 1
0001 MATCH CV0($char) "a": 0002, "b": 0003, "c": 0003, "d": 0004, "e": 0005, "f": 0005, "g": 0006, "h": 0007, "i": 0007, default: 0008
0002 RETURN string("a")
0003 RETURN string("b, c")
0004 RETURN string("d")
0005 RETURN string("e, f")
0006 RETURN string("g")
0007 RETURN string("h, i")
0008 MATCH_ERROR CV0($char)
0001 MATCH CV0($char) "a": 0003, "b": 0004, "c": 0004, "d": 0005, "e": 0006, "f": 0006, "g": 0007, "h": 0008, "i": 0008, default: 0002
0002 MATCH_ERROR CV0($char)
0003 RETURN string("a")
0004 RETURN string("b, c")
0005 RETURN string("d")
0006 RETURN string("e, f")
0007 RETURN string("g")
0008 RETURN string("h, i")
string(1) "a"
string(4) "b, c"
string(4) "b, c"