Skip to content

Commit 1310944

Browse files
committed
Avoid throw expression leaks
1 parent 786e0ae commit 1310944

File tree

3 files changed

+48
-5
lines changed

3 files changed

+48
-5
lines changed

Zend/tests/throw/leaks.phpt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
--TEST--
2+
throw expression should not leak temporaries
3+
--FILE--
4+
<?php
5+
6+
try {
7+
new stdClass(throw new Exception);
8+
} catch (Exception $e) {
9+
echo "Caught\n";
10+
}
11+
12+
try {
13+
$a = [];
14+
($a + [1]) + throw new Exception;
15+
} catch (Exception $e) {
16+
echo "Caught\n";
17+
}
18+
19+
try {
20+
@throw new Exception;
21+
} catch (Exception $e) {
22+
echo "Caught\n";
23+
}
24+
var_dump(error_reporting());
25+
26+
?>
27+
--EXPECT--
28+
Caught
29+
Caught
30+
Caught
31+
int(32767)

Zend/zend_compile.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4562,10 +4562,13 @@ void zend_compile_throw(znode *result, zend_ast *ast) /* {{{ */
45624562
znode expr_node;
45634563
zend_compile_expr(&expr_node, expr_ast);
45644564

4565-
zend_emit_op(NULL, ZEND_THROW, &expr_node, NULL);
4566-
4567-
result->op_type = IS_CONST;
4568-
ZVAL_BOOL(&result->u.constant, 1);
4565+
zend_op *opline = zend_emit_op(NULL, ZEND_THROW, &expr_node, NULL);
4566+
if (result) {
4567+
/* Mark this as an "expression throw" for opcache. */
4568+
opline->extended_value = 1;
4569+
result->op_type = IS_CONST;
4570+
ZVAL_BOOL(&result->u.constant, 1);
4571+
}
45694572
}
45704573
/* }}} */
45714574

@@ -8799,6 +8802,9 @@ void zend_compile_stmt(zend_ast *ast) /* {{{ */
87998802
case ZEND_AST_HALT_COMPILER:
88008803
zend_compile_halt_compiler(ast);
88018804
break;
8805+
case ZEND_AST_THROW:
8806+
zend_compile_throw(NULL, ast);
8807+
return;
88028808
default:
88038809
{
88048810
znode result;

ext/opcache/Optimizer/zend_cfg.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,11 +296,17 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b
296296
case ZEND_RETURN_BY_REF:
297297
case ZEND_GENERATOR_RETURN:
298298
case ZEND_EXIT:
299-
case ZEND_THROW:
300299
if (i + 1 < op_array->last) {
301300
BB_START(i + 1);
302301
}
303302
break;
303+
case ZEND_THROW:
304+
/* Don't treat THROW as terminator if it's used in expression context,
305+
* as we may lose live ranges when eliminating unreachable code. */
306+
if (!opline->extended_value && i + 1 < op_array->last) {
307+
BB_START(i + 1);
308+
}
309+
break;
304310
case ZEND_INCLUDE_OR_EVAL:
305311
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
306312
case ZEND_GENERATOR_CREATE:

0 commit comments

Comments
 (0)