@@ -240,11 +240,25 @@ static zend_result spl_object_storage_detach(spl_SplObjectStorage *intern, zend_
240240 return ret ;
241241} /* }}}*/
242242
243+ /* TODO: make this an official Zend API? */
244+ #define SPL_SAFE_HASH_FOREACH_PTR (_ht , _ptr ) do { \
245+ const HashTable *__ht = (_ht); \
246+ zval *_z = __ht->arPacked; \
247+ for (uint32_t _idx = 0; _idx < __ht->nNumUsed; _idx++, _z = ZEND_HASH_ELEMENT(__ht, _idx)) { \
248+ if (UNEXPECTED(Z_ISUNDEF_P(_z))) continue; \
249+ _ptr = Z_PTR_P(_z);
250+
243251static void spl_object_storage_addall (spl_SplObjectStorage * intern , spl_SplObjectStorage * other ) { /* {{{ */
244252 spl_SplObjectStorageElement * element ;
245253
246- ZEND_HASH_FOREACH_PTR (& other -> storage , element ) {
247- spl_object_storage_attach (intern , element -> obj , & element -> inf );
254+ SPL_SAFE_HASH_FOREACH_PTR (& other -> storage , element ) {
255+ zval zv ;
256+ zend_object * obj = element -> obj ;
257+ GC_ADDREF (obj );
258+ ZVAL_COPY (& zv , & element -> inf );
259+ spl_object_storage_attach (intern , obj , & zv );
260+ zval_ptr_dtor (& zv );
261+ OBJ_RELEASE (obj );
248262 } ZEND_HASH_FOREACH_END ();
249263
250264 intern -> index = 0 ;
@@ -626,10 +640,13 @@ PHP_METHOD(SplObjectStorage, removeAllExcept)
626640
627641 other = Z_SPLOBJSTORAGE_P (obj );
628642
629- ZEND_HASH_FOREACH_PTR (& intern -> storage , element ) {
630- if (!spl_object_storage_contains (other , element -> obj )) {
631- spl_object_storage_detach (intern , element -> obj );
643+ SPL_SAFE_HASH_FOREACH_PTR (& intern -> storage , element ) {
644+ zend_object * elem_obj = element -> obj ;
645+ GC_ADDREF (elem_obj );
646+ if (!spl_object_storage_contains (other , elem_obj )) {
647+ spl_object_storage_detach (intern , elem_obj );
632648 }
649+ OBJ_RELEASE (elem_obj );
633650 } ZEND_HASH_FOREACH_END ();
634651
635652 zend_hash_internal_pointer_reset_ex (& intern -> storage , & intern -> pos );
0 commit comments