Skip to content

Commit 7147226

Browse files
committed
Fix GH-19094: Attaching class with no Iterator implementation to MultipleIterator causes crash
Closes GH-19097.
1 parent 85a49d4 commit 7147226

File tree

3 files changed

+80
-1
lines changed

3 files changed

+80
-1
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ PHP NEWS
4747
on object destruction). (nielsdos)
4848
. Fix memory leak when URL parsing fails in redirect. (Girgias)
4949

50+
- SPL:
51+
. Fixed bug GH-19094 (Attaching class with no Iterator implementation to
52+
MultipleIterator causes crash). (nielsdos)
53+
5054
- Standard:
5155
. Fix misleading errors in printf(). (nielsdos)
5256
. Fix RCN violations in array functions. (nielsdos)

ext/spl/spl_observer.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ PHPAPI zend_class_entry *spl_ce_SplObjectStorage;
4343
PHPAPI zend_class_entry *spl_ce_MultipleIterator;
4444

4545
PHPAPI zend_object_handlers spl_handler_SplObjectStorage;
46+
static zend_object_handlers spl_handler_MultipleIterator; /* TODO: make public ? */
4647

4748
/* Bit flags for marking internal functionality overridden by SplObjectStorage subclasses. */
4849
#define SOS_OVERRIDDEN_READ_DIMENSION 1
@@ -493,6 +494,20 @@ static void spl_object_storage_write_dimension(zend_object *object, zval *offset
493494
spl_object_storage_attach_handle(intern, Z_OBJ_P(offset), inf);
494495
}
495496

497+
static void spl_multiple_iterator_write_dimension(zend_object *object, zval *offset, zval *inf)
498+
{
499+
spl_SplObjectStorage *intern = spl_object_storage_from_obj(object);
500+
if (UNEXPECTED(offset == NULL || Z_TYPE_P(offset) != IS_OBJECT || (intern->flags & SOS_OVERRIDDEN_WRITE_DIMENSION))) {
501+
zend_std_write_dimension(object, offset, inf);
502+
return;
503+
}
504+
if (UNEXPECTED(!Z_OBJCE_P(offset)->iterator_funcs_ptr || !Z_OBJCE_P(offset)->iterator_funcs_ptr->zf_valid)) {
505+
zend_type_error("Can only attach objects that implement the Iterator interface");
506+
return;
507+
}
508+
spl_object_storage_attach_handle(intern, Z_OBJ_P(offset), inf);
509+
}
510+
496511
static void spl_object_storage_unset_dimension(zend_object *object, zval *offset)
497512
{
498513
spl_SplObjectStorage *intern = spl_object_storage_from_obj(object);
@@ -1352,9 +1367,13 @@ PHP_MINIT_FUNCTION(spl_observer)
13521367
spl_handler_SplObjectStorage.has_dimension = spl_object_storage_has_dimension;
13531368
spl_handler_SplObjectStorage.unset_dimension = spl_object_storage_unset_dimension;
13541369

1370+
memcpy(&spl_handler_MultipleIterator, &spl_handler_SplObjectStorage, sizeof(zend_object_handlers));
1371+
1372+
spl_handler_MultipleIterator.write_dimension = spl_multiple_iterator_write_dimension;
1373+
13551374
spl_ce_MultipleIterator = register_class_MultipleIterator(zend_ce_iterator);
13561375
spl_ce_MultipleIterator->create_object = spl_SplObjectStorage_new;
1357-
spl_ce_MultipleIterator->default_object_handlers = &spl_handler_SplObjectStorage;
1376+
spl_ce_MultipleIterator->default_object_handlers = &spl_handler_MultipleIterator;
13581377

13591378
return SUCCESS;
13601379
}

ext/spl/tests/gh19094.phpt

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
--TEST--
2+
GH-19094 (Attaching class with no Iterator implementation to MultipleIterator causes crash)
3+
--FILE--
4+
<?php
5+
6+
class MyIterator implements Iterator {
7+
public function valid(): bool {
8+
return false;
9+
}
10+
11+
public function current(): mixed {
12+
return null;
13+
}
14+
15+
public function key(): string {
16+
return "";
17+
}
18+
19+
public function next(): void {
20+
}
21+
22+
public function rewind(): void {
23+
}
24+
}
25+
26+
class MyAggregate implements IteratorAggregate {
27+
public function getIterator(): Traversable
28+
{
29+
throw new Error;
30+
}
31+
}
32+
33+
$cls = new MultipleIterator();
34+
$canary = new stdClass;
35+
try {
36+
$cls[$canary] = 1;
37+
} catch (TypeError $e) {
38+
echo $e->getMessage(), "\n";
39+
}
40+
try {
41+
$cls[new MyAggregate] = 1;
42+
} catch (TypeError $e) {
43+
echo $e->getMessage(), "\n";
44+
}
45+
$cls[new MyIterator] = 1;
46+
try {
47+
$cls->key();
48+
} catch (RuntimeException $e) {
49+
echo $e->getMessage(), "\n";
50+
}
51+
52+
?>
53+
--EXPECT--
54+
Can only attach objects that implement the Iterator interface
55+
Can only attach objects that implement the Iterator interface
56+
Called key() with non valid sub iterator

0 commit comments

Comments
 (0)