Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2480362

Browse files
Root arguments of internal frames
1 parent 8547fba commit 2480362

File tree

3 files changed

+112
-4
lines changed

3 files changed

+112
-4
lines changed

‎Zend/tests/gc/gh13687-003.phpt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
--TEST--
2+
GH-13687 003: Result operand may leak if GC is triggered before consumption
3+
--FILE--
4+
<?php
5+
6+
class A {
7+
public $cycle;
8+
public function __construct() { $this->cycle = $this; }
9+
}
10+
class B {
11+
public function get() {
12+
return new A();
13+
}
14+
}
15+
class Debug {
16+
public function __debugInfo() {
17+
gc_collect_cycles();
18+
return [];
19+
}
20+
}
21+
22+
$c = new B();
23+
var_dump($c->get(), new Debug);
24+
25+
?>
26+
==DONE==
27+
--EXPECTF--
28+
object(A)#%d (1) {
29+
["cycle"]=>
30+
*RECURSION*
31+
}
32+
object(Debug)#%d (0) {
33+
}
34+
==DONE==

‎Zend/tests/gc/gh13687-004.phpt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
GH-13687 004: Result operand may leak if GC is triggered before consumption
3+
--ENV--
4+
func=call_user_func
5+
--FILE--
6+
<?php
7+
8+
class A {
9+
public $cycle;
10+
public function __construct() { $this->cycle = $this; }
11+
}
12+
class B {
13+
public function get() {
14+
return new A();
15+
}
16+
}
17+
class Debug {
18+
public function __debugInfo() {
19+
gc_collect_cycles();
20+
return [];
21+
}
22+
}
23+
24+
$c = new B();
25+
getenv('func')(fn (...$args) => gc_collect_cycles(), a: $c->get());
26+
27+
?>
28+
==DONE==
29+
--EXPECT--
30+
==DONE==

‎Zend/zend_gc.c

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2221,7 +2221,7 @@ static void zend_gc_check_root_tmpvars(void) {
22212221
return;
22222222
}
22232223

2224-
if (ZEND_USER_CODE(ex->func->type)) {
2224+
if (ex->func&&ZEND_USER_CODE(ex->func->type)) {
22252225
const zend_op *op = ex->opline;
22262226
if (op->result_type & (IS_VAR | IS_TMP_VAR)) {
22272227
switch (op->opcode) {
@@ -2249,7 +2249,29 @@ static void zend_gc_check_root_tmpvars(void) {
22492249

22502250
for (; ex; ex = ex->prev_execute_data) {
22512251
zend_function *func = ex->func;
2252-
if (!func || !ZEND_USER_CODE(func->type)) {
2252+
if (!func) {
2253+
continue;
2254+
}
2255+
2256+
if (!ZEND_USER_CODE(func->type)) {
2257+
/* For internal frames, arguments are not consumed yet, so we must
2258+
* root them. */
2259+
zend_execute_data *caller = ex->prev_execute_data;
2260+
if (!caller->func || !ZEND_USER_CODE(caller->func->type)) {
2261+
continue;
2262+
}
2263+
2264+
uint32_t num_args = ZEND_CALL_NUM_ARGS(ex);
2265+
if (EXPECTED(num_args > 0)) {
2266+
zval *p = ZEND_CALL_ARG(ex, 1);
2267+
do {
2268+
if (Z_COLLECTABLE_P(p)) {
2269+
gc_check_possible_root(Z_COUNTED_P(p));
2270+
}
2271+
p++;
2272+
} while (--num_args);
2273+
}
2274+
22532275
continue;
22542276
}
22552277

@@ -2282,7 +2304,7 @@ static void zend_gc_remove_root_tmpvars(void) {
22822304
return;
22832305
}
22842306

2285-
if (ZEND_USER_CODE(ex->func->type)) {
2307+
if (ex->func&&ZEND_USER_CODE(ex->func->type)) {
22862308
const zend_op *op = ex->opline;
22872309
if (op->result_type & (IS_VAR | IS_TMP_VAR)) {
22882310
switch (op->opcode) {
@@ -2310,7 +2332,29 @@ static void zend_gc_remove_root_tmpvars(void) {
23102332

23112333
for (; ex; ex = ex->prev_execute_data) {
23122334
zend_function *func = ex->func;
2313-
if (!func || !ZEND_USER_CODE(func->type)) {
2335+
if (!func) {
2336+
continue;
2337+
}
2338+
2339+
if (!ZEND_USER_CODE(func->type)) {
2340+
/* For internal frames, arguments are live, so we should unroot
2341+
* them. */
2342+
zend_execute_data *caller = ex->prev_execute_data;
2343+
if (!caller->func || !ZEND_USER_CODE(caller->func->type)) {
2344+
continue;
2345+
}
2346+
2347+
uint32_t num_args = ZEND_CALL_NUM_ARGS(ex);
2348+
if (EXPECTED(num_args > 0)) {
2349+
zval *p = ZEND_CALL_ARG(ex, 1);
2350+
do {
2351+
if (Z_COLLECTABLE_P(p)) {
2352+
GC_REMOVE_FROM_BUFFER(Z_COUNTED_P(p));
2353+
}
2354+
p++;
2355+
} while (--num_args);
2356+
}
2357+
23142358
continue;
23152359
}
23162360

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /