@@ -255,6 +255,8 @@ static HashTable* spl_object_storage_debug_info(zval *obj, int *is_temp TSRMLS_D
255
255
* is_temp = 0 ;
256
256
257
257
props = Z_OBJPROP_P (obj );
258
+ zend_hash_del (props , "\x00gcdata" , sizeof ("\x00gcdata" ));
259
+
258
260
if (intern -> debug_info == NULL ) {
259
261
ALLOC_HASHTABLE (intern -> debug_info );
260
262
ZEND_INIT_SYMTABLE_EX (intern -> debug_info , zend_hash_num_elements (props ) + 1 , 0 );
@@ -269,10 +271,11 @@ static HashTable* spl_object_storage_debug_info(zval *obj, int *is_temp TSRMLS_D
269
271
zend_hash_internal_pointer_reset_ex (& intern -> storage , & pos );
270
272
while (zend_hash_get_current_data_ex (& intern -> storage , (void * * )& element , & pos ) == SUCCESS ) {
271
273
php_spl_object_hash (element -> obj , md5str TSRMLS_CC );
272
- Z_ADDREF_P (element -> obj );
273
- Z_ADDREF_P (element -> inf );
274
274
MAKE_STD_ZVAL (tmp );
275
275
array_init (tmp );
276
+ /* Incrementing the refcount of obj and inf would confuse the garbage collector.
277
+ * Prefer to null the destructor */
278
+ Z_ARRVAL_P (tmp )-> pDestructor = NULL ;
276
279
add_assoc_zval_ex (tmp , "obj" , sizeof ("obj" ), element -> obj );
277
280
add_assoc_zval_ex (tmp , "inf" , sizeof ("inf" ), element -> inf );
278
281
add_assoc_zval_ex (storage , md5str , 33 , tmp );
@@ -288,6 +291,63 @@ static HashTable* spl_object_storage_debug_info(zval *obj, int *is_temp TSRMLS_D
288
291
}
289
292
/* }}} */
290
293
294
+ /* overriden for garbage collection
295
+ * This is very hacky, but unfortunately the garbage collector can only query objects for
296
+ * dependencies through get_properties */
297
+ static HashTable * spl_object_storage_get_properties (zval * obj TSRMLS_DC ) /* {{{ */
298
+ {
299
+ spl_SplObjectStorage * intern = (spl_SplObjectStorage * )zend_object_store_get_object (obj TSRMLS_CC );
300
+ spl_SplObjectStorageElement * element ;
301
+ HashTable * props ;
302
+ HashPosition pos ;
303
+ zval * gcdata_arr = NULL ,
304
+ * * gcdata_arr_pp ;
305
+
306
+ props = std_object_handlers .get_properties (obj TSRMLS_CC );
307
+
308
+ if (!GC_G (gc_active )) {
309
+ zend_hash_del (props , "\x00gcdata" , sizeof ("\x00gcdata" ));
310
+ return props ;
311
+ }
312
+
313
+ if (props -> nApplyCount > 0 ) {
314
+ return props ;
315
+ }
316
+
317
+ /* clean \x00gcdata, as it may be out of date */
318
+ if (zend_hash_find (props , "\x00gcdata" , sizeof ("\x00gcdata" ), (void * * ) & gcdata_arr_pp ) == SUCCESS ) {
319
+ gcdata_arr = * gcdata_arr_pp ;
320
+ zend_hash_clean (Z_ARRVAL_P (gcdata_arr ));
321
+ }
322
+
323
+ /* destroy intern->debug_info, as it's holding references to the zvals */
324
+ if (intern -> debug_info != NULL ) {
325
+ zend_hash_destroy (intern -> debug_info );
326
+ efree (intern -> debug_info );
327
+ intern -> debug_info = NULL ;
328
+ }
329
+
330
+ if (gcdata_arr == NULL ) {
331
+ MAKE_STD_ZVAL (gcdata_arr );
332
+ array_init (gcdata_arr );
333
+ /* don't decrease refcount of members when destroying */
334
+ Z_ARRVAL_P (gcdata_arr )-> pDestructor = NULL ;
335
+
336
+ /* name starts with \x00 to make tampering in user-land more difficult */
337
+ zend_hash_add (props , "\x00gcdata" , sizeof ("\x00gcdata" ), & gcdata_arr , sizeof (gcdata_arr ), NULL );
338
+ }
339
+
340
+ zend_hash_internal_pointer_reset_ex (& intern -> storage , & pos );
341
+ while (zend_hash_get_current_data_ex (& intern -> storage , (void * * )& element , & pos ) == SUCCESS ) {
342
+ add_next_index_zval (gcdata_arr , element -> obj );
343
+ add_next_index_zval (gcdata_arr , element -> inf );
344
+ zend_hash_move_forward_ex (& intern -> storage , & pos );
345
+ }
346
+
347
+ return props ;
348
+ }
349
+ /* }}} */
350
+
291
351
static int spl_object_storage_compare_info (spl_SplObjectStorageElement * e1 , spl_SplObjectStorageElement * e2 TSRMLS_DC ) /* {{{ */
292
352
{
293
353
zval result ;
@@ -1064,6 +1124,7 @@ PHP_MINIT_FUNCTION(spl_observer)
1064
1124
REGISTER_SPL_STD_CLASS_EX (SplObjectStorage , spl_SplObjectStorage_new , spl_funcs_SplObjectStorage );
1065
1125
memcpy (& spl_handler_SplObjectStorage , zend_get_std_object_handlers (), sizeof (zend_object_handlers ));
1066
1126
1127
+ spl_handler_SplObjectStorage .get_properties = spl_object_storage_get_properties ;
1067
1128
spl_handler_SplObjectStorage .get_debug_info = spl_object_storage_debug_info ;
1068
1129
spl_handler_SplObjectStorage .compare_objects = spl_object_storage_compare_objects ;
1069
1130
spl_handler_SplObjectStorage .clone_obj = spl_object_storage_clone ;
0 commit comments