@@ -45,6 +45,8 @@ static zend_object_handlers spl_handler_MultipleIterator;
4545#define SOS_OVERRIDDEN_WRITE_DIMENSION 2
4646#define SOS_OVERRIDDEN_UNSET_DIMENSION 4
4747
48+ ZEND_TLS uint32_t spl_object_storage_get_hash_running ;
49+
4850typedef struct _spl_SplObjectStorage { /* {{{ */
4951 HashTable storage ;
5052 zend_long index ;
@@ -69,6 +71,16 @@ static inline spl_SplObjectStorage *spl_object_storage_from_obj(zend_object *obj
6971
7072#define Z_SPLOBJSTORAGE_P (zv ) spl_object_storage_from_obj(Z_OBJ_P((zv)))
7173
74+ static zend_always_inline bool spl_object_storage_disallow_mutation_during_get_hash (void )
75+ {
76+ if (UNEXPECTED (spl_object_storage_get_hash_running )) {
77+ zend_throw_error (NULL , "Modification of SplObjectStorage during getHash() is prohibited" );
78+ return true;
79+ }
80+
81+ return false;
82+ }
83+
7284static void spl_SplObjectStorage_free_storage (zend_object * object ) /* {{{ */
7385{
7486 spl_SplObjectStorage * intern = spl_object_storage_from_obj (object );
@@ -83,7 +95,10 @@ static zend_result spl_object_storage_get_hash(zend_hash_key *key, spl_SplObject
8395 zval param ;
8496 zval rv ;
8597 ZVAL_OBJ (& param , obj );
98+ ZVAL_UNDEF (& rv );
99+ spl_object_storage_get_hash_running ++ ;
86100 zend_call_method_with_1_params (& intern -> std , intern -> std .ce , & intern -> fptr_get_hash , "getHash" , & rv , & param );
101+ spl_object_storage_get_hash_running -- ;
87102 if (UNEXPECTED (Z_ISUNDEF (rv ))) {
88103 /* An exception has occurred */
89104 return FAILURE ;
@@ -176,6 +191,10 @@ static spl_SplObjectStorageElement *spl_object_storage_attach_handle(spl_SplObje
176191
177192static spl_SplObjectStorageElement * spl_object_storage_attach (spl_SplObjectStorage * intern , zend_object * obj , zval * inf ) /* {{{ */
178193{
194+ if (UNEXPECTED (spl_object_storage_disallow_mutation_during_get_hash ())) {
195+ return NULL ;
196+ }
197+
179198 if (EXPECTED (!(intern -> flags & SOS_OVERRIDDEN_WRITE_DIMENSION ))) {
180199 return spl_object_storage_attach_handle (intern , obj , inf );
181200 }
@@ -221,6 +240,10 @@ static spl_SplObjectStorageElement *spl_object_storage_attach(spl_SplObjectStora
221240
222241static zend_result spl_object_storage_detach (spl_SplObjectStorage * intern , zend_object * obj ) /* {{{ */
223242{
243+ if (UNEXPECTED (spl_object_storage_disallow_mutation_during_get_hash ())) {
244+ return FAILURE ;
245+ }
246+
224247 if (EXPECTED (!(intern -> flags & SOS_OVERRIDDEN_UNSET_DIMENSION ))) {
225248 return zend_hash_index_del (& intern -> storage , obj -> handle );
226249 }
@@ -247,20 +270,25 @@ static zend_result spl_object_storage_detach(spl_SplObjectStorage *intern, zend_
247270 if (UNEXPECTED(Z_ISUNDEF_P(_z))) continue; \
248271 _ptr = Z_PTR_P(_z);
249272
250- static void spl_object_storage_addall (spl_SplObjectStorage * intern , spl_SplObjectStorage * other ) { /* {{{ */
273+ static zend_result spl_object_storage_addall (spl_SplObjectStorage * intern , spl_SplObjectStorage * other ) { /* {{{ */
251274 spl_SplObjectStorageElement * element ;
252275
253276 SPL_SAFE_HASH_FOREACH_PTR (& other -> storage , element ) {
254277 zval zv ;
255278 zend_object * obj = element -> obj ;
256279 GC_ADDREF (obj );
257280 ZVAL_COPY (& zv , & element -> inf );
258- spl_object_storage_attach (intern , obj , & zv );
281+ if (UNEXPECTED (!spl_object_storage_attach (intern , obj , & zv ))) {
282+ zval_ptr_dtor (& zv );
283+ OBJ_RELEASE (obj );
284+ return FAILURE ;
285+ }
259286 zval_ptr_dtor (& zv );
260287 OBJ_RELEASE (obj );
261288 } ZEND_HASH_FOREACH_END ();
262289
263290 intern -> index = 0 ;
291+ return SUCCESS ;
264292} /* }}} */
265293
266294#define SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE (class_type , zstr_method ) \
@@ -446,6 +474,9 @@ PHP_METHOD(SplObjectStorage, attach)
446474 Z_PARAM_ZVAL (inf )
447475 ZEND_PARSE_PARAMETERS_END ();
448476 spl_object_storage_attach (intern , obj , inf );
477+ if (UNEXPECTED (EG (exception ))) {
478+ RETURN_THROWS ();
479+ }
449480} /* }}} */
450481
451482// todo: make spl_object_storage_has_dimension return bool as well
@@ -494,6 +525,10 @@ static zval *spl_object_storage_read_dimension(zend_object *object, zval *offset
494525static void spl_object_storage_write_dimension (zend_object * object , zval * offset , zval * inf )
495526{
496527 spl_SplObjectStorage * intern = spl_object_storage_from_obj (object );
528+ if (UNEXPECTED (spl_object_storage_disallow_mutation_during_get_hash ())) {
529+ return ;
530+ }
531+
497532 if (UNEXPECTED (offset == NULL || Z_TYPE_P (offset ) != IS_OBJECT || (intern -> flags & SOS_OVERRIDDEN_WRITE_DIMENSION ))) {
498533 zend_std_write_dimension (object , offset , inf );
499534 return ;
@@ -504,6 +539,10 @@ static void spl_object_storage_write_dimension(zend_object *object, zval *offset
504539static void spl_multiple_iterator_write_dimension (zend_object * object , zval * offset , zval * inf )
505540{
506541 spl_SplObjectStorage * intern = spl_object_storage_from_obj (object );
542+ if (UNEXPECTED (spl_object_storage_disallow_mutation_during_get_hash ())) {
543+ return ;
544+ }
545+
507546 if (UNEXPECTED (offset == NULL || Z_TYPE_P (offset ) != IS_OBJECT || (intern -> flags & SOS_OVERRIDDEN_WRITE_DIMENSION ))) {
508547 zend_std_write_dimension (object , offset , inf );
509548 return ;
@@ -518,6 +557,10 @@ static void spl_multiple_iterator_write_dimension(zend_object *object, zval *off
518557static void spl_object_storage_unset_dimension (zend_object * object , zval * offset )
519558{
520559 spl_SplObjectStorage * intern = spl_object_storage_from_obj (object );
560+ if (UNEXPECTED (spl_object_storage_disallow_mutation_during_get_hash ())) {
561+ return ;
562+ }
563+
521564 if (UNEXPECTED (Z_TYPE_P (offset ) != IS_OBJECT || (intern -> flags & SOS_OVERRIDDEN_UNSET_DIMENSION ))) {
522565 zend_std_unset_dimension (object , offset );
523566 return ;
@@ -535,6 +578,9 @@ PHP_METHOD(SplObjectStorage, detach)
535578 Z_PARAM_OBJ (obj )
536579 ZEND_PARSE_PARAMETERS_END ();
537580 spl_object_storage_detach (intern , obj );
581+ if (UNEXPECTED (EG (exception ))) {
582+ RETURN_THROWS ();
583+ }
538584
539585 zend_hash_internal_pointer_reset_ex (& intern -> storage , & intern -> pos );
540586 intern -> index = 0 ;
@@ -566,6 +612,9 @@ PHP_METHOD(SplObjectStorage, offsetGet)
566612 ZEND_PARSE_PARAMETERS_END ();
567613
568614 if (spl_object_storage_get_hash (& key , intern , obj ) == FAILURE ) {
615+ if (UNEXPECTED (EG (exception ))) {
616+ RETURN_THROWS ();
617+ }
569618 RETURN_NULL ();
570619 }
571620
@@ -592,7 +641,9 @@ PHP_METHOD(SplObjectStorage, addAll)
592641
593642 other = Z_SPLOBJSTORAGE_P (obj );
594643
595- spl_object_storage_addall (intern , other );
644+ if (UNEXPECTED (spl_object_storage_addall (intern , other ) == FAILURE )) {
645+ RETURN_THROWS ();
646+ }
596647
597648 RETURN_LONG (zend_hash_num_elements (& intern -> storage ));
598649} /* }}} */
@@ -614,6 +665,9 @@ PHP_METHOD(SplObjectStorage, removeAll)
614665 zend_hash_internal_pointer_reset (& other -> storage );
615666 while ((element = zend_hash_get_current_data_ptr (& other -> storage )) != NULL ) {
616667 if (spl_object_storage_detach (intern , element -> obj ) == FAILURE ) {
668+ if (UNEXPECTED (EG (exception ))) {
669+ RETURN_THROWS ();
670+ }
617671 zend_hash_move_forward (& other -> storage );
618672 }
619673 }
@@ -641,8 +695,19 @@ PHP_METHOD(SplObjectStorage, removeAllExcept)
641695 SPL_SAFE_HASH_FOREACH_PTR (& intern -> storage , element ) {
642696 zend_object * elem_obj = element -> obj ;
643697 GC_ADDREF (elem_obj );
644- if (!spl_object_storage_contains (other , elem_obj )) {
645- spl_object_storage_detach (intern , elem_obj );
698+ bool contains = spl_object_storage_contains (other , elem_obj );
699+ if (UNEXPECTED (EG (exception ))) {
700+ OBJ_RELEASE (elem_obj );
701+ RETURN_THROWS ();
702+ }
703+ if (!contains ) {
704+ if (spl_object_storage_detach (intern , elem_obj ) == FAILURE ) {
705+ OBJ_RELEASE (elem_obj );
706+ if (UNEXPECTED (EG (exception ))) {
707+ RETURN_THROWS ();
708+ }
709+ continue ;
710+ }
646711 }
647712 OBJ_RELEASE (elem_obj );
648713 } ZEND_HASH_FOREACH_END ();
@@ -663,7 +728,13 @@ PHP_METHOD(SplObjectStorage, contains)
663728 ZEND_PARSE_PARAMETERS_START (1 , 1 )
664729 Z_PARAM_OBJ (obj )
665730 ZEND_PARSE_PARAMETERS_END ();
666- RETURN_BOOL (spl_object_storage_contains (intern , obj ));
731+
732+ bool contains = spl_object_storage_contains (intern , obj );
733+ if (UNEXPECTED (EG (exception ))) {
734+ RETURN_THROWS ();
735+ }
736+
737+ RETURN_BOOL (contains );
667738} /* }}} */
668739
669740/* {{{ Determine number of objects in storage */
@@ -753,6 +824,9 @@ PHP_METHOD(SplObjectStorage, setInfo)
753824 if (zend_parse_parameters (ZEND_NUM_ARGS (), "z" , & inf ) == FAILURE ) {
754825 RETURN_THROWS ();
755826 }
827+ if (UNEXPECTED (spl_object_storage_disallow_mutation_during_get_hash ())) {
828+ RETURN_THROWS ();
829+ }
756830
757831 if ((element = zend_hash_get_current_data_ptr_ex (& intern -> storage , & intern -> pos )) == NULL ) {
758832 RETURN_NULL ();
@@ -947,6 +1021,10 @@ PHP_METHOD(SplObjectStorage, unserialize)
9471021
9481022 if (spl_object_storage_get_hash (& key , intern , Z_OBJ_P (entry )) == FAILURE ) {
9491023 zval_ptr_dtor (& inf );
1024+ if (EG (exception )) {
1025+ PHP_VAR_UNSERIALIZE_DESTROY (var_hash );
1026+ RETURN_THROWS ();
1027+ }
9501028 goto outexcept ;
9511029 }
9521030 pelement = spl_object_storage_get (intern , & key );
@@ -960,6 +1038,14 @@ PHP_METHOD(SplObjectStorage, unserialize)
9601038 var_push_dtor (& var_hash , & obj );
9611039 }
9621040 element = spl_object_storage_attach (intern , Z_OBJ_P (entry ), Z_ISUNDEF (inf )?NULL :& inf );
1041+ if (UNEXPECTED (!element )) {
1042+ zval_ptr_dtor (& inf );
1043+ if (EG (exception )) {
1044+ PHP_VAR_UNSERIALIZE_DESTROY (var_hash );
1045+ RETURN_THROWS ();
1046+ }
1047+ goto outexcept ;
1048+ }
9631049 var_replace (& var_hash , & inf , & element -> inf );
9641050 zval_ptr_dtor (& inf );
9651051 }
@@ -1055,7 +1141,9 @@ PHP_METHOD(SplObjectStorage, __unserialize)
10551141 }
10561142
10571143 ZVAL_DEREF (val );
1058- spl_object_storage_attach (intern , Z_OBJ_P (key ), val );
1144+ if (UNEXPECTED (!spl_object_storage_attach (intern , Z_OBJ_P (key ), val ))) {
1145+ RETURN_THROWS ();
1146+ }
10591147 key = NULL ;
10601148 } else {
10611149 key = val ;
@@ -1151,8 +1239,14 @@ PHP_METHOD(MultipleIterator, attachIterator)
11511239 }
11521240
11531241 spl_object_storage_attach (intern , iterator , & zinfo );
1242+ if (UNEXPECTED (EG (exception ))) {
1243+ RETURN_THROWS ();
1244+ }
11541245 } else {
11551246 spl_object_storage_attach (intern , iterator , NULL );
1247+ if (UNEXPECTED (EG (exception ))) {
1248+ RETURN_THROWS ();
1249+ }
11561250 }
11571251}
11581252/* }}} */
@@ -1167,6 +1261,9 @@ PHP_METHOD(MultipleIterator, detachIterator)
11671261 RETURN_THROWS ();
11681262 }
11691263 spl_object_storage_detach (intern , Z_OBJ_P (iterator ));
1264+ if (UNEXPECTED (EG (exception ))) {
1265+ RETURN_THROWS ();
1266+ }
11701267
11711268 zend_hash_internal_pointer_reset_ex (& intern -> storage , & intern -> pos );
11721269 intern -> index = 0 ;
0 commit comments