Skip to content

Commit c68cdcd

Browse files
authored
PHPC-1839 Fix accessing referenced strings (#1223)
* PHPC-1839 Fix accessing referenced non-interned strings * Use ZVAL_DEREF * Update tests to not require a live server * Use correct case for method names
1 parent 1dcfb80 commit c68cdcd

File tree

5 files changed

+185
-0
lines changed

5 files changed

+185
-0
lines changed

src/contrib/php_array_api.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,12 @@ PHP_ARRAY_FETCH_TYPE_MAP(zend_bool, bool)
281281
*/
282282
static inline
283283
PAA_LONG php_array_zval_to_long(zval *z) {
284+
try_again:
284285
if (!z) { return 0; }
285286
switch(Z_TYPE_P(z)) {
287+
case IS_REFERENCE:
288+
ZVAL_DEREF(z);
289+
goto try_again;
286290
case IS_NULL: return 0;
287291
#ifdef ZEND_ENGINE_3
288292
case IS_FALSE: return 0;
@@ -315,8 +319,12 @@ PHP_ARRAY_FETCH_TYPE_MAP(PAA_LONG, long)
315319
*/
316320
static inline
317321
double php_array_zval_to_double(zval *z) {
322+
try_again:
318323
if (!z) { return 0.0; }
319324
switch (Z_TYPE_P(z)) {
325+
case IS_REFERENCE:
326+
ZVAL_DEREF(z);
327+
goto try_again;
320328
case IS_NULL: return 0.0;
321329
#ifdef ZEND_ENGINE_3
322330
case IS_FALSE: return 0.0;
@@ -357,10 +365,14 @@ static inline
357365
char *php_array_zval_to_string(zval *z, int *plen, zend_bool *pfree) {
358366
*plen = 0;
359367
*pfree = 0;
368+
try_again:
360369
if (!z) { return NULL; }
361370
switch (Z_TYPE_P(z)) {
362371
case IS_NULL:
363372
return (char *)"";
373+
case IS_REFERENCE:
374+
ZVAL_DEREF(z);
375+
goto try_again;
364376
case IS_STRING:
365377
*plen = Z_STRLEN_P(z);
366378
return Z_STRVAL_P(z);

tests/bson/bug1839-001.phpt

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
--TEST--
2+
PHPC-1839: Referenced, out-of-scope, non-interned string in typeMap
3+
--FILE--
4+
<?php
5+
require_once __DIR__ . "/../utils/basic.inc";
6+
7+
function createTypemap()
8+
{
9+
// Assemble the string so as to not have an interned string
10+
$rootValue = chr(ord('a')) . 'rray';
11+
$documentValue = chr(ord('a')) . 'rray';
12+
13+
// Use a reference to this non-interned string in the type map
14+
$typemap = ['root' => &$rootValue, 'document' => &$documentValue];
15+
16+
return $typemap;
17+
}
18+
19+
$typemap = createTypemap();
20+
$bson = MongoDB\BSON\fromPhp((object) []);
21+
22+
echo "Before:\n";
23+
debug_zval_dump($typemap);
24+
25+
MongoDB\BSON\toPHP($bson, $typemap);
26+
27+
echo "After:\n";
28+
debug_zval_dump($typemap);
29+
30+
?>
31+
===DONE===
32+
<?php exit(0); ?>
33+
--EXPECT--
34+
Before:
35+
array(2) refcount(2){
36+
["root"]=>
37+
string(5) "array" refcount(1)
38+
["document"]=>
39+
string(5) "array" refcount(1)
40+
}
41+
After:
42+
array(2) refcount(2){
43+
["root"]=>
44+
string(5) "array" refcount(1)
45+
["document"]=>
46+
string(5) "array" refcount(1)
47+
}
48+
===DONE===

tests/bson/bug1839-002.phpt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
--TEST--
2+
PHPC-1839: Referenced, local, non-interned string in typeMap
3+
--FILE--
4+
<?php
5+
require_once __DIR__ . "/../utils/basic.inc";
6+
7+
// Assemble the string so as to not have an interned string
8+
$rootValue = chr(ord('a')) . 'rray';
9+
$documentValue = chr(ord('a')) . 'rray';
10+
11+
$typemap = ['root' => &$rootValue, 'document' => &$documentValue];
12+
$bson = MongoDB\BSON\fromPhp((object) []);
13+
14+
echo "Before:\n";
15+
debug_zval_dump($typemap);
16+
17+
MongoDB\BSON\toPHP($bson, $typemap);
18+
19+
echo "After:\n";
20+
debug_zval_dump($typemap);
21+
22+
?>
23+
===DONE===
24+
<?php exit(0); ?>
25+
--EXPECT--
26+
Before:
27+
array(2) refcount(2){
28+
["root"]=>
29+
&string(5) "array" refcount(1)
30+
["document"]=>
31+
&string(5) "array" refcount(1)
32+
}
33+
After:
34+
array(2) refcount(2){
35+
["root"]=>
36+
&string(5) "array" refcount(1)
37+
["document"]=>
38+
&string(5) "array" refcount(1)
39+
}
40+
===DONE===

tests/bson/bug1839-003.phpt

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
--TEST--
2+
PHPC-1839: Referenced, out-of-scope, interned string in typeMap
3+
--FILE--
4+
<?php
5+
require_once __DIR__ . "/../utils/basic.inc";
6+
7+
function createTypemap()
8+
{
9+
$rootValue = 'array';
10+
$documentValue = 'array';
11+
12+
$typemap = ['root' => &$rootValue, 'document' => &$documentValue];
13+
14+
return $typemap;
15+
}
16+
17+
$typemap = createTypemap();
18+
$bson = MongoDB\BSON\fromPhp((object) []);
19+
20+
echo "Before:\n";
21+
debug_zval_dump($typemap);
22+
23+
MongoDB\BSON\toPHP($bson, $typemap);
24+
25+
echo "After:\n";
26+
debug_zval_dump($typemap);
27+
28+
?>
29+
===DONE===
30+
<?php exit(0); ?>
31+
--EXPECT--
32+
Before:
33+
array(2) refcount(2){
34+
["root"]=>
35+
string(5) "array" refcount(1)
36+
["document"]=>
37+
string(5) "array" refcount(1)
38+
}
39+
After:
40+
array(2) refcount(2){
41+
["root"]=>
42+
string(5) "array" refcount(1)
43+
["document"]=>
44+
string(5) "array" refcount(1)
45+
}
46+
===DONE===

tests/bson/bug1839-004.phpt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
--TEST--
2+
PHPC-1839: Referenced, local, interned string in typeMap
3+
--FILE--
4+
<?php
5+
require_once __DIR__ . "/../utils/basic.inc";
6+
7+
$rootValue = 'array';
8+
$documentValue = 'array';
9+
10+
$typemap = ['root' => &$rootValue, 'document' => &$documentValue];
11+
$bson = MongoDB\BSON\fromPhp((object) []);
12+
13+
echo "Before:\n";
14+
debug_zval_dump($typemap);
15+
16+
MongoDB\BSON\toPHP($bson, $typemap);
17+
18+
echo "After:\n";
19+
debug_zval_dump($typemap);
20+
21+
?>
22+
===DONE===
23+
<?php exit(0); ?>
24+
--EXPECT--
25+
Before:
26+
array(2) refcount(2){
27+
["root"]=>
28+
&string(5) "array" refcount(1)
29+
["document"]=>
30+
&string(5) "array" refcount(1)
31+
}
32+
After:
33+
array(2) refcount(2){
34+
["root"]=>
35+
&string(5) "array" refcount(1)
36+
["document"]=>
37+
&string(5) "array" refcount(1)
38+
}
39+
===DONE===

0 commit comments

Comments
 (0)