Skip to content

Commit 35148db

Browse files
committed
Fix GH-21639: Protect frameless implode args
1 parent f7eb5ef commit 35148db

2 files changed

Lines changed: 73 additions & 0 deletions

File tree

ext/standard/string.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,8 +1084,12 @@ PHP_FUNCTION(implode)
10841084

10851085
ZEND_FRAMELESS_FUNCTION(implode, 1)
10861086
{
1087+
zval arg1_tmp;
10871088
zval *pieces;
10881089

1090+
ZVAL_COPY_DEREF(&arg1_tmp, arg1);
1091+
arg1 = &arg1_tmp;
1092+
10891093
/* Manual parsing for more accurate error message. */
10901094
if (!zend_parse_arg_array(arg1, &pieces, /* null_check */ false, /* or_object */ false)) { \
10911095
zend_type_error(
@@ -1101,14 +1105,22 @@ ZEND_FRAMELESS_FUNCTION(implode, 1)
11011105
php_implode(str, Z_ARR_P(pieces), return_value);
11021106

11031107
flf_clean:;
1108+
zval_ptr_dtor(&arg1_tmp);
11041109
}
11051110

11061111
ZEND_FRAMELESS_FUNCTION(implode, 2)
11071112
{
1113+
zval arg1_tmp;
1114+
zval arg2_tmp;
11081115
zval str_tmp;
11091116
zend_string *str;
11101117
zval *pieces;
11111118

1119+
ZVAL_COPY_DEREF(&arg1_tmp, arg1);
1120+
arg1 = &arg1_tmp;
1121+
ZVAL_COPY_DEREF(&arg2_tmp, arg2);
1122+
arg2 = &arg2_tmp;
1123+
11121124
Z_FLF_PARAM_STR(1, str, str_tmp);
11131125
Z_FLF_PARAM_ARRAY_OR_NULL(2, pieces);
11141126

@@ -1125,6 +1137,8 @@ ZEND_FRAMELESS_FUNCTION(implode, 2)
11251137

11261138
flf_clean:;
11271139
Z_FLF_PARAM_FREE_STR(1, str_tmp);
1140+
zval_ptr_dtor(&arg2_tmp);
1141+
zval_ptr_dtor(&arg1_tmp);
11281142
}
11291143

11301144
#define STRTOK_TABLE(p) BG(strtok_table)[(unsigned char) *p]
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
--TEST--
2+
GH-21639: Frameless implode keeps volatile arguments alive
3+
--FILE--
4+
<?php
5+
class C {
6+
public function __toString(): string {
7+
global $separator, $pieces;
8+
9+
$separator = null;
10+
$pieces = null;
11+
12+
return "C";
13+
}
14+
}
15+
16+
$separator = str_repeat(",", 1) . " ";
17+
$pieces = [new C(), 42];
18+
19+
var_dump(implode($separator, $pieces));
20+
var_dump($separator, $pieces);
21+
22+
class MutatingSeparator {
23+
public function __toString(): string {
24+
global $piecesFromSeparator;
25+
26+
$piecesFromSeparator = null;
27+
28+
return ", ";
29+
}
30+
}
31+
32+
$piecesFromSeparator = ["A", "B"];
33+
34+
var_dump(implode(new MutatingSeparator(), $piecesFromSeparator));
35+
var_dump($piecesFromSeparator);
36+
37+
class D {
38+
public function __toString(): string {
39+
global $oneArgPieces;
40+
41+
$oneArgPieces = null;
42+
43+
return "D";
44+
}
45+
}
46+
47+
$oneArgPieces = [new D(), 42];
48+
49+
var_dump(implode($oneArgPieces));
50+
var_dump($oneArgPieces);
51+
?>
52+
--EXPECT--
53+
string(5) "C, 42"
54+
NULL
55+
NULL
56+
string(4) "A, B"
57+
NULL
58+
string(3) "D42"
59+
NULL

0 commit comments

Comments
 (0)