Skip to content

Commit 733d664

Browse files
committed
Merge branch 'PHP-8.5' into PHP-8.6
* PHP-8.5: Fix GH-23626: OPcache: orphaned temporaries cause leaks and assertions
2 parents 8d39747 + 6de713d commit 733d664

3 files changed

Lines changed: 64 additions & 4 deletions

File tree

‎NEWS‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ PHP NEWS
8686
static calls in trait methods shared by several classes). (jorgsowa,
8787
mgoulart)
8888
. Fix block pass dropping ZEND_FAST_CALL OP2 definition. (Mrmaxmeier)
89+
. Fixed bug GH-23626 (orphaned temporaries cause leaks and assertions).
90+
(ndossche, khaledalam)
8991

9092
- OpenSSL:
9193
. Fixed bug GH-24784 (openssl_pkcs7_read() and openssl_cms_read() overwrite

‎Zend/zend_compile.c‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7302,10 +7302,9 @@ static void zend_compile_match(znode *result, zend_ast *ast)
73027302
if (opline->op1_type == IS_CONST) {
73037303
Z_TRY_ADDREF_P(CT_CONSTANT(opline->op1));
73047304
}
7305-
if (arms->children == 0) {
7306-
/* Mark this as an "expression throw" for opcache. */
7307-
opline->extended_value = ZEND_THROW_IS_EXPR;
7308-
}
7305+
/* Mark this as an "expression throw" for opcache.
7306+
* Even if there are arms, they may become unreachable after optimization, which loses live ranges. */
7307+
opline->extended_value = ZEND_THROW_IS_EXPR;
73097308
}
73107309

73117310
for (uint32_t i = 0; i < arms->children; ++i) {

‎ext/opcache/tests/gh23626.phpt‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
--TEST--
2+
GH-23626: OPcache: orphaned temporaries cause leaks and assertions
3+
--CREDITS--
4+
Mrmaxmeier
5+
--EXTENSIONS--
6+
opcache
7+
--INI--
8+
opcache.enable=1
9+
opcache.enable_cli=1
10+
opcache.optimization_level=-1
11+
--FILE--
12+
<?php
13+
class D {
14+
public function __construct(public string $name) {}
15+
public function __clone() { $this->name .= '-clone'; }
16+
public function __destruct() { echo "destruct {$this->name}\n"; }
17+
}
18+
19+
function test_assert($u) {
20+
(function () use ($u) {}) ** match (1) { 2 => 3 };
21+
}
22+
23+
function one($o) {
24+
(clone $o) ** match (1) { 2 => 3 };
25+
}
26+
27+
function two($a, $b) {
28+
(clone $a) ** ((clone $b) ** match (1) { 2 => 3 });
29+
}
30+
31+
function rope($o) {
32+
return "x{$o->name}y" . match (1) { 2 => 3 };
33+
}
34+
35+
$a = new D('a');
36+
$b = new D('b');
37+
38+
foreach (['test_assert' => [1], 'one' => [$a], 'two' => [$a, $b], 'rope' => [$a]] as $fn => $args) {
39+
try {
40+
$fn(...$args);
41+
} catch (\UnhandledMatchError $e) {
42+
echo "$fn: ", $e->getMessage(), "\n";
43+
}
44+
}
45+
46+
unset($a, $b, $args, $e);
47+
echo "done\n";
48+
?>
49+
--EXPECT--
50+
test_assert: Unhandled match case 1
51+
destruct a-clone
52+
one: Unhandled match case 1
53+
destruct a-clone
54+
destruct b-clone
55+
two: Unhandled match case 1
56+
rope: Unhandled match case 1
57+
destruct b
58+
destruct a
59+
done

0 commit comments

Comments
 (0)