Skip to content

Commit a56e512

Browse files
committed
ext/spl: Fix unnecessible value written when using null as key
1 parent a7e7ab1 commit a56e512

File tree

5 files changed

+113
-22
lines changed

5 files changed

+113
-22
lines changed

ext/spl/spl_array.c

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -465,33 +465,22 @@ static void spl_array_write_dimension_ex(int check_inherited, zend_object *objec
465465
spl_array_object *intern = spl_array_from_obj(object);
466466
HashTable *ht;
467467
spl_hash_key key;
468-
469-
/* Cannot append if backing value is an object */
470-
if (offset == NULL && spl_array_is_object(intern)) {
471-
zend_throw_error(NULL, "Cannot append properties to objects, use %s::offsetSet() instead", ZSTR_VAL(object->ce->name));
472-
return;
473-
}
474-
475-
if (check_inherited && intern->fptr_offset_set) {
476-
zval tmp;
477-
478-
if (!offset) {
479-
ZVAL_NULL(&tmp);
480-
offset = &tmp;
481-
}
482-
zend_call_method_with_2_params(object, object->ce, &intern->fptr_offset_set, "offsetSet", NULL, offset, value);
483-
return;
484-
}
468+
uint32_t refcount = 0;
485469

486470
if (intern->nApplyCount > 0) {
487471
zend_throw_error(NULL, "Modification of ArrayObject during sorting is prohibited");
488472
return;
489473
}
490474

491-
Z_TRY_ADDREF_P(value);
475+
/* We are appending */
476+
if (!offset) {
477+
/* Cannot append if backing value is an object */
478+
if (spl_array_is_object(intern)) {
479+
zend_throw_error(NULL, "Cannot append properties to objects, use %s::offsetSet() instead", ZSTR_VAL(object->ce->name));
480+
return;
481+
}
492482

493-
uint32_t refcount = 0;
494-
if (!offset || Z_TYPE_P(offset) == IS_NULL) {
483+
Z_TRY_ADDREF_P(value);
495484
ht = spl_array_get_hash_table(intern);
496485
refcount = spl_array_set_refcount(intern->is_child, ht, 1);
497486
zend_hash_next_index_insert(ht, value);
@@ -502,6 +491,19 @@ static void spl_array_write_dimension_ex(int check_inherited, zend_object *objec
502491
return;
503492
}
504493

494+
if (check_inherited && intern->fptr_offset_set) {
495+
zval tmp;
496+
497+
if (!offset) {
498+
ZVAL_NULL(&tmp);
499+
offset = &tmp;
500+
}
501+
zend_call_method_with_2_params(object, object->ce, &intern->fptr_offset_set, "offsetSet", NULL, offset, value);
502+
return;
503+
}
504+
505+
Z_TRY_ADDREF_P(value);
506+
505507
if (get_hash_key(&key, intern, offset) == FAILURE) {
506508
zend_illegal_container_offset(object->ce->name, offset, BP_VAR_W);
507509
zval_ptr_dtor(value);
@@ -514,6 +516,7 @@ static void spl_array_write_dimension_ex(int check_inherited, zend_object *objec
514516
zend_hash_update_ind(ht, key.key, value);
515517
spl_hash_key_release(&key);
516518
} else {
519+
ZEND_ASSERT(!spl_array_is_object(intern));
517520
zend_hash_index_update(ht, key.h, value);
518521
}
519522

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
--TEST--
2+
Overwritting default append method
3+
--EXTENSIONS--
4+
spl
5+
--FILE--
6+
<?php
7+
8+
class Dummy {}
9+
10+
class OverWriteAppend extends ArrayObject
11+
{
12+
private $data;
13+
14+
function __construct($v)
15+
{
16+
$this->data = [];
17+
parent::__construct($v);
18+
}
19+
20+
function append($value): void
21+
{
22+
$this->data[] = $value;
23+
}
24+
}
25+
26+
$d = new Dummy();
27+
$ao = new OverWriteAppend($d);
28+
29+
$ao->append("value1");
30+
var_dump($ao);
31+
?>
32+
--EXPECT--
33+
object(OverWriteAppend)#2 (2) {
34+
["data":"OverWriteAppend":private]=>
35+
array(1) {
36+
[0]=>
37+
string(6) "value1"
38+
}
39+
["storage":"ArrayObject":private]=>
40+
object(Dummy)#1 (0) {
41+
}
42+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
--TEST--
2+
Using null as key must make the value accessible
3+
--EXTENSIONS--
4+
spl
5+
--FILE--
6+
<?php
7+
class MyClass {}
8+
$c = new MyClass();
9+
10+
$ao = new ArrayObject($c);
11+
12+
$ao[null] = "null key";
13+
var_dump($c);
14+
var_dump($c->{""});
15+
var_dump($ao[null]);
16+
?>
17+
--EXPECT--
18+
object(MyClass)#1 (1) {
19+
[""]=>
20+
string(8) "null key"
21+
}
22+
string(8) "null key"
23+
string(8) "null key"
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
Using null as offset must make the value accessible
3+
--EXTENSIONS--
4+
spl
5+
--FILE--
6+
<?php
7+
class MyClass {}
8+
$c = new MyClass();
9+
10+
$ao = new ArrayObject($c);
11+
12+
$ao->offsetSet(null, "null key");
13+
var_dump($ao->offsetExists(null));
14+
var_dump($ao->offsetGet(null));
15+
var_dump($c);
16+
var_dump($c->{""});
17+
?>
18+
--EXPECT--
19+
bool(true)
20+
string(8) "null key"
21+
object(MyClass)#1 (1) {
22+
[""]=>
23+
string(8) "null key"
24+
}
25+
string(8) "null key"

ext/spl/tests/bug33136.phpt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,8 @@ var_dump(count($arrayObj));
4949
--EXPECT--
5050
Initiate Obj
5151
Assign values
52-
Collection::offsetSet(NULL,foo)
5352
Collection::offsetGet(0)
5453
string(3) "foo"
55-
Collection::offsetSet(NULL,bar)
5654
Collection::offsetGet(0)
5755
string(3) "foo"
5856
Collection::offsetGet(1)

0 commit comments

Comments
 (0)