Skip to content

Commit c9762be

Browse files
committed
Don't treat expression exit as terminator
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.
1 parent 757c127 commit c9762be

File tree

3 files changed

+14
-6
lines changed

3 files changed

+14
-6
lines changed

Zend/Optimizer/zend_cfg.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,13 +299,13 @@ ZEND_API int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, u
299299
case ZEND_RETURN:
300300
case ZEND_RETURN_BY_REF:
301301
case ZEND_GENERATOR_RETURN:
302-
case ZEND_EXIT:
303302
case ZEND_MATCH_ERROR:
304303
case ZEND_VERIFY_NEVER_TYPE:
305304
if (i + 1 < op_array->last) {
306305
BB_START(i + 1);
307306
}
308307
break;
308+
case ZEND_EXIT:
309309
case ZEND_THROW:
310310
/* Don't treat THROW as terminator if it's used in expression context,
311311
* as we may lose live ranges when eliminating unreachable code. */

Zend/tests/throw/leaks.phpt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ try {
2323
}
2424
var_dump(error_reporting());
2525

26+
// Exit also unwinds and thus has the same basic problem.
27+
new stdClass(exit);
28+
2629
?>
2730
--EXPECT--
2831
Caught

Zend/zend_compile.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9045,17 +9045,21 @@ static void zend_compile_print(znode *result, zend_ast *ast) /* {{{ */
90459045
static void zend_compile_exit(znode *result, zend_ast *ast) /* {{{ */
90469046
{
90479047
zend_ast *expr_ast = ast->child[0];
9048+
znode expr_node;
90489049

90499050
if (expr_ast) {
9050-
znode expr_node;
90519051
zend_compile_expr(&expr_node, expr_ast);
9052-
zend_emit_op(NULL, ZEND_EXIT, &expr_node, NULL);
90539052
} else {
9054-
zend_emit_op(NULL, ZEND_EXIT, NULL, NULL);
9053+
expr_node.op_type = IS_UNUSED;
90559054
}
90569055

9057-
result->op_type = IS_CONST;
9058-
ZVAL_TRUE(&result->u.constant);
9056+
zend_op *opline = zend_emit_op(NULL, ZEND_EXIT, &expr_node, NULL);
9057+
if (result) {
9058+
/* Mark this as an "expression throw" for opcache. */
9059+
opline->extended_value = ZEND_THROW_IS_EXPR;
9060+
result->op_type = IS_CONST;
9061+
ZVAL_TRUE(&result->u.constant);
9062+
}
90599063
}
90609064
/* }}} */
90619065

@@ -9999,6 +10003,7 @@ static void zend_compile_stmt(zend_ast *ast) /* {{{ */
999910003
zend_compile_halt_compiler(ast);
1000010004
break;
1000110005
case ZEND_AST_THROW:
10006+
case ZEND_AST_EXIT:
1000210007
zend_compile_expr(NULL, ast);
1000310008
break;
1000410009
default:

0 commit comments

Comments
 (0)