Skip to content

Commit

Permalink
Don't treat expression exit as terminator
Browse files Browse the repository at this point in the history
Same as with throw expressions, this may remove later temporary
consuming instructions and thus eliminate live ranges, resulting
in a memory leak. We make use of the same hack and don't consider
exit a terminator if used in an expression context.
  • Loading branch information
nikic committed Sep 23, 2021
1 parent 757c127 commit c9762be
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 6 deletions.
2 changes: 1 addition & 1 deletion Zend/Optimizer/zend_cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,13 +299,13 @@ ZEND_API int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, u
case ZEND_RETURN:
case ZEND_RETURN_BY_REF:
case ZEND_GENERATOR_RETURN:
case ZEND_EXIT:
case ZEND_MATCH_ERROR:
case ZEND_VERIFY_NEVER_TYPE:
if (i + 1 < op_array->last) {
BB_START(i + 1);
}
break;
case ZEND_EXIT:
case ZEND_THROW:
/* Don't treat THROW as terminator if it's used in expression context,
* as we may lose live ranges when eliminating unreachable code. */
Expand Down
3 changes: 3 additions & 0 deletions Zend/tests/throw/leaks.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ try {
}
var_dump(error_reporting());

// Exit also unwinds and thus has the same basic problem.
new stdClass(exit);

?>
--EXPECT--
Caught
Expand Down
15 changes: 10 additions & 5 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -9045,17 +9045,21 @@ static void zend_compile_print(znode *result, zend_ast *ast) /* {{{ */
static void zend_compile_exit(znode *result, zend_ast *ast) /* {{{ */
{
zend_ast *expr_ast = ast->child[0];
znode expr_node;

if (expr_ast) {
znode expr_node;
zend_compile_expr(&expr_node, expr_ast);
zend_emit_op(NULL, ZEND_EXIT, &expr_node, NULL);
} else {
zend_emit_op(NULL, ZEND_EXIT, NULL, NULL);
expr_node.op_type = IS_UNUSED;
}

result->op_type = IS_CONST;
ZVAL_TRUE(&result->u.constant);
zend_op *opline = zend_emit_op(NULL, ZEND_EXIT, &expr_node, NULL);
if (result) {
/* Mark this as an "expression throw" for opcache. */
opline->extended_value = ZEND_THROW_IS_EXPR;
result->op_type = IS_CONST;
ZVAL_TRUE(&result->u.constant);
}
}
/* }}} */

Expand Down Expand Up @@ -9999,6 +10003,7 @@ static void zend_compile_stmt(zend_ast *ast) /* {{{ */
zend_compile_halt_compiler(ast);
break;
case ZEND_AST_THROW:
case ZEND_AST_EXIT:
zend_compile_expr(NULL, ast);
break;
default:
Expand Down

0 comments on commit c9762be

Please sign in to comment.