@@ -241,11 +241,25 @@ static zend_result spl_object_storage_detach(spl_SplObjectStorage *intern, zend_
241241 return ret ;
242242} /* }}}*/
243243
244+ /* TODO: make this an official Zend API? */
245+ #define SPL_SAFE_HASH_FOREACH_PTR (_ht , _ptr ) do { \
246+ const HashTable *__ht = (_ht); \
247+ zval *_z = __ht->arPacked; \
248+ for (uint32_t _idx = 0; _idx < __ht->nNumUsed; _idx++, _z = ZEND_HASH_ELEMENT(__ht, _idx)) { \
249+ if (UNEXPECTED(Z_ISUNDEF_P(_z))) continue; \
250+ _ptr = Z_PTR_P(_z);
251+
244252static void spl_object_storage_addall (spl_SplObjectStorage * intern , spl_SplObjectStorage * other ) { /* {{{ */
245253 spl_SplObjectStorageElement * element ;
246254
247- ZEND_HASH_FOREACH_PTR (& other -> storage , element ) {
248- spl_object_storage_attach (intern , element -> obj , & element -> inf );
255+ SPL_SAFE_HASH_FOREACH_PTR (& other -> storage , element ) {
256+ zval zv ;
257+ zend_object * obj = element -> obj ;
258+ GC_ADDREF (obj );
259+ ZVAL_COPY (& zv , & element -> inf );
260+ spl_object_storage_attach (intern , obj , & zv );
261+ zval_ptr_dtor (& zv );
262+ OBJ_RELEASE (obj );
249263 } ZEND_HASH_FOREACH_END ();
250264
251265 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