Skip to content

Commit 22f8a54

Browse files
committed
Disallow data classes for SplObjectStorage and WeakMap
1 parent 512fee9 commit 22f8a54

File tree

4 files changed

+178
-8
lines changed

4 files changed

+178
-8
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--TEST--
2+
Nested WeakMap for same object key
3+
--FILE--
4+
<?php
5+
6+
data class DC {}
7+
8+
function test($c) {
9+
$map = new WeakMap();
10+
$dc = new DC();
11+
12+
try {
13+
$c($map, $dc);
14+
} catch (Error $e) {
15+
echo $e->getMessage(), "\n";
16+
}
17+
}
18+
19+
test(function ($map, $dc) {
20+
var_dump($map[$dc]);
21+
});
22+
test(function ($map, $dc) {
23+
$map[$dc] = 1;
24+
});
25+
test(function ($map, $dc) {
26+
unset($map[$dc]);
27+
});
28+
test(function ($map, $dc) {
29+
var_dump(isset($map[$dc]));
30+
});
31+
32+
?>
33+
--EXPECT--
34+
Instance of data class DC may not be used as key
35+
Instance of data class DC may not be used as key
36+
Instance of data class DC may not be used as key
37+
Instance of data class DC may not be used as key

Zend/zend_weakrefs.c

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,22 @@ static void zend_weakmap_free_obj(zend_object *object)
341341
zend_object_std_dtor(&wm->std);
342342
}
343343

344+
static zend_result zend_weakmap_check_offset(zval *offset)
345+
{
346+
if (Z_TYPE_P(offset) != IS_OBJECT) {
347+
zend_type_error("WeakMap key must be an object");
348+
return FAILURE;
349+
}
350+
351+
zend_object *obj = Z_OBJ_P(offset);
352+
if (UNEXPECTED(obj->ce->ce_flags & ZEND_ACC_DATA_CLASS)) {
353+
zend_type_error("Instance of data class %s may not be used as key", ZSTR_VAL(obj->ce->name));
354+
return FAILURE;
355+
}
356+
357+
return SUCCESS;
358+
}
359+
344360
static zval *zend_weakmap_read_dimension(zend_object *object, zval *offset, int type, zval *rv)
345361
{
346362
if (offset == NULL) {
@@ -349,8 +365,7 @@ static zval *zend_weakmap_read_dimension(zend_object *object, zval *offset, int
349365
}
350366

351367
ZVAL_DEREF(offset);
352-
if (Z_TYPE_P(offset) != IS_OBJECT) {
353-
zend_type_error("WeakMap key must be an object");
368+
if (zend_weakmap_check_offset(offset) == FAILURE) {
354369
return NULL;
355370
}
356371

@@ -380,8 +395,7 @@ static void zend_weakmap_write_dimension(zend_object *object, zval *offset, zval
380395
}
381396

382397
ZVAL_DEREF(offset);
383-
if (Z_TYPE_P(offset) != IS_OBJECT) {
384-
zend_type_error("WeakMap key must be an object");
398+
if (zend_weakmap_check_offset(offset) == FAILURE) {
385399
return;
386400
}
387401

@@ -409,8 +423,7 @@ static void zend_weakmap_write_dimension(zend_object *object, zval *offset, zval
409423
static int zend_weakmap_has_dimension(zend_object *object, zval *offset, int check_empty)
410424
{
411425
ZVAL_DEREF(offset);
412-
if (Z_TYPE_P(offset) != IS_OBJECT) {
413-
zend_type_error("WeakMap key must be an object");
426+
if (zend_weakmap_check_offset(offset) == FAILURE) {
414427
return 0;
415428
}
416429

@@ -429,8 +442,7 @@ static int zend_weakmap_has_dimension(zend_object *object, zval *offset, int che
429442
static void zend_weakmap_unset_dimension(zend_object *object, zval *offset)
430443
{
431444
ZVAL_DEREF(offset);
432-
if (Z_TYPE_P(offset) != IS_OBJECT) {
433-
zend_type_error("WeakMap key must be an object");
445+
if (zend_weakmap_check_offset(offset) == FAILURE) {
434446
return;
435447
}
436448

ext/spl/spl_observer.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,15 @@ void spl_SplObjectStorage_free_storage(zend_object *object) /* {{{ */
8282
zend_hash_destroy(&intern->storage);
8383
} /* }}} */
8484

85+
static zend_result spl_check_data_class(zend_object *obj)
86+
{
87+
if (UNEXPECTED(obj->ce->ce_flags & ZEND_ACC_DATA_CLASS)) {
88+
zend_type_error("Instance of data class %s may not be used as key", ZSTR_VAL(obj->ce->name));
89+
return FAILURE;
90+
}
91+
return SUCCESS;
92+
}
93+
8594
static zend_result spl_object_storage_get_hash(zend_hash_key *key, spl_SplObjectStorage *intern, zend_object *obj) {
8695
if (UNEXPECTED(intern->fptr_get_hash)) {
8796
zval param;
@@ -437,11 +446,24 @@ PHP_METHOD(SplObjectStorage, attach)
437446
Z_PARAM_OPTIONAL
438447
Z_PARAM_ZVAL(inf)
439448
ZEND_PARSE_PARAMETERS_END();
449+
450+
if (UNEXPECTED(spl_check_data_class(obj) == FAILURE)) {
451+
RETURN_THROWS();
452+
}
453+
440454
spl_object_storage_attach(intern, obj, inf);
441455
} /* }}} */
442456

443457
static int spl_object_storage_has_dimension(zend_object *object, zval *offset, int check_empty)
444458
{
459+
if (EXPECTED(offset)) {
460+
ZVAL_DEREF(offset);
461+
if (Z_TYPE_P(offset) == IS_OBJECT
462+
&& UNEXPECTED(spl_check_data_class(Z_OBJ_P(offset)) == FAILURE)) {
463+
return 0;
464+
}
465+
}
466+
445467
spl_SplObjectStorage *intern = spl_object_storage_from_obj(object);
446468
if (UNEXPECTED(offset == NULL || Z_TYPE_P(offset) != IS_OBJECT || (intern->flags & SOS_OVERRIDDEN_READ_DIMENSION))) {
447469
/* Can't optimize empty()/isset() check if getHash, offsetExists, or offsetGet is overridden */
@@ -461,6 +483,14 @@ static int spl_object_storage_has_dimension(zend_object *object, zval *offset, i
461483

462484
static zval *spl_object_storage_read_dimension(zend_object *object, zval *offset, int type, zval *rv)
463485
{
486+
if (EXPECTED(offset)) {
487+
ZVAL_DEREF(offset);
488+
if (Z_TYPE_P(offset) == IS_OBJECT
489+
&& UNEXPECTED(spl_check_data_class(Z_OBJ_P(offset)) == FAILURE)) {
490+
return NULL;
491+
}
492+
}
493+
464494
spl_SplObjectStorage *intern = spl_object_storage_from_obj(object);
465495
if (UNEXPECTED(offset == NULL || Z_TYPE_P(offset) != IS_OBJECT || (intern->flags & SOS_OVERRIDDEN_READ_DIMENSION))) {
466496
/* Can't optimize it if getHash, offsetExists, or offsetGet is overridden */
@@ -484,6 +514,14 @@ static zval *spl_object_storage_read_dimension(zend_object *object, zval *offset
484514

485515
static void spl_object_storage_write_dimension(zend_object *object, zval *offset, zval *inf)
486516
{
517+
if (EXPECTED(offset)) {
518+
ZVAL_DEREF(offset);
519+
if (Z_TYPE_P(offset) == IS_OBJECT
520+
&& UNEXPECTED(spl_check_data_class(Z_OBJ_P(offset)) == FAILURE)) {
521+
return;
522+
}
523+
}
524+
487525
spl_SplObjectStorage *intern = spl_object_storage_from_obj(object);
488526
if (UNEXPECTED(offset == NULL || Z_TYPE_P(offset) != IS_OBJECT || (intern->flags & SOS_OVERRIDDEN_WRITE_DIMENSION))) {
489527
zend_std_write_dimension(object, offset, inf);
@@ -494,6 +532,14 @@ static void spl_object_storage_write_dimension(zend_object *object, zval *offset
494532

495533
static void spl_object_storage_unset_dimension(zend_object *object, zval *offset)
496534
{
535+
if (EXPECTED(offset)) {
536+
ZVAL_DEREF(offset);
537+
if (Z_TYPE_P(offset) == IS_OBJECT
538+
&& UNEXPECTED(spl_check_data_class(Z_OBJ_P(offset)) == FAILURE)) {
539+
return;
540+
}
541+
}
542+
497543
spl_SplObjectStorage *intern = spl_object_storage_from_obj(object);
498544
if (UNEXPECTED(Z_TYPE_P(offset) != IS_OBJECT || (intern->flags & SOS_OVERRIDDEN_UNSET_DIMENSION))) {
499545
zend_std_unset_dimension(object, offset);
@@ -511,6 +557,11 @@ PHP_METHOD(SplObjectStorage, detach)
511557
ZEND_PARSE_PARAMETERS_START(1, 1)
512558
Z_PARAM_OBJ(obj)
513559
ZEND_PARSE_PARAMETERS_END();
560+
561+
if (UNEXPECTED(spl_check_data_class(obj) == FAILURE)) {
562+
RETURN_THROWS();
563+
}
564+
514565
spl_object_storage_detach(intern, obj);
515566

516567
zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
@@ -526,6 +577,10 @@ PHP_METHOD(SplObjectStorage, getHash)
526577
Z_PARAM_OBJ(obj)
527578
ZEND_PARSE_PARAMETERS_END();
528579

580+
if (UNEXPECTED(spl_check_data_class(obj) == FAILURE)) {
581+
RETURN_THROWS();
582+
}
583+
529584
RETURN_NEW_STR(php_spl_object_hash(obj));
530585

531586
} /* }}} */
@@ -542,6 +597,10 @@ PHP_METHOD(SplObjectStorage, offsetGet)
542597
Z_PARAM_OBJ(obj)
543598
ZEND_PARSE_PARAMETERS_END();
544599

600+
if (UNEXPECTED(spl_check_data_class(obj) == FAILURE)) {
601+
RETURN_THROWS();
602+
}
603+
545604
if (spl_object_storage_get_hash(&key, intern, obj) == FAILURE) {
546605
RETURN_NULL();
547606
}
@@ -637,6 +696,11 @@ PHP_METHOD(SplObjectStorage, contains)
637696
ZEND_PARSE_PARAMETERS_START(1, 1)
638697
Z_PARAM_OBJ(obj)
639698
ZEND_PARSE_PARAMETERS_END();
699+
700+
if (UNEXPECTED(spl_check_data_class(obj) == FAILURE)) {
701+
RETURN_THROWS();
702+
}
703+
640704
RETURN_BOOL(spl_object_storage_contains(intern, obj));
641705
} /* }}} */
642706

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
--TEST--
2+
SplObjectStorage disallows data classes
3+
--FILE--
4+
<?php
5+
6+
data class DC {}
7+
8+
function test($c) {
9+
$map = new SplObjectStorage();
10+
$dc = new DC();
11+
12+
try {
13+
$c($map, $dc);
14+
} catch (Error $e) {
15+
echo $e->getMessage(), "\n";
16+
}
17+
}
18+
19+
test(function ($map, $dc) {
20+
var_dump($map[$dc]);
21+
});
22+
test(function ($map, $dc) {
23+
$map[$dc] = 1;
24+
});
25+
test(function ($map, $dc) {
26+
unset($map[$dc]);
27+
});
28+
test(function ($map, $dc) {
29+
var_dump(isset($map[$dc]));
30+
});
31+
test(function ($map, $dc) {
32+
$map->attach($dc, 1);
33+
});
34+
test(function ($map, $dc) {
35+
$map->detach($dc);
36+
});
37+
test(function ($map, $dc) {
38+
var_dump($map->getHash($dc));
39+
});
40+
test(function ($map, $dc) {
41+
var_dump($map->offsetGet($dc));
42+
});
43+
test(function ($map, $dc) {
44+
var_dump($map->contains($dc));
45+
});
46+
47+
?>
48+
--EXPECT--
49+
Instance of data class DC may not be used as key
50+
Instance of data class DC may not be used as key
51+
Instance of data class DC may not be used as key
52+
Instance of data class DC may not be used as key
53+
Instance of data class DC may not be used as key
54+
Instance of data class DC may not be used as key
55+
Instance of data class DC may not be used as key
56+
Instance of data class DC may not be used as key
57+
Instance of data class DC may not be used as key

0 commit comments

Comments
 (0)