@@ -543,6 +543,61 @@ PHP_FUNCTION(var_export)
543
543
544
544
static void php_var_serialize_intern (smart_str * buf , zval * struc , HashTable * var_hash TSRMLS_DC );
545
545
546
+ /**
547
+ * Iterates over zvals captured during serialization, and releases/decrements them
548
+ */
549
+ void php_var_serialize_release_zval_chain (zval_chain * zval_refs ) {
550
+ zval_chain * node = BG (serialize ).zval_refs ;
551
+ zval_chain * next = NULL ;
552
+ int count = 0 ;
553
+
554
+ while (node != NULL ) {
555
+ #if 0
556
+ fprintf (stderr , "- zval chain %d: ref (%d) %p\n" , count , Z_REFCOUNT_P (node -> value ), node -> value );
557
+ #endif
558
+ count ++ ;
559
+ next = node -> next ;
560
+ zval_ptr_dtor (& (node -> value ));
561
+ //Z_DELREF_P(node->value);
562
+ efree (node );
563
+ node = next ;
564
+ }
565
+ }
566
+
567
+ /**
568
+ * Increments zval reference count in order to keep it alive for the duration of object graph serialization;
569
+ * registers zval in threadlocal list of zvals to decrement/release when topmost serialization frame is popped
570
+ */
571
+ static inline void php_var_serialize_capture_zval (zval * var ) {
572
+ // increment reference count
573
+ zend_uint refcount = Z_ADDREF_P (var );
574
+ //zval_copy_ctor(var);
575
+
576
+ // store on threadlocal serialization list for decrement when serialization frame is popped
577
+ zval_chain * new_zval = emalloc (sizeof (zval_chain ));
578
+ new_zval -> value = var ;
579
+ new_zval -> next = NULL ;
580
+ zval_chain * * zval_refs = & BG (serialize ).zval_refs ;
581
+
582
+ // optimize later:
583
+ // new_zval->next = *zval_refs;
584
+ // *zval_refs = new_zval;
585
+
586
+ // singly linked list - find the end and append
587
+ int i = 0 ;
588
+ while (* zval_refs ) {
589
+ zval_refs = & ((* * zval_refs ).next );
590
+ i ++ ;
591
+ }
592
+ * zval_refs = new_zval ;
593
+
594
+ #if 0
595
+ fprintf (stderr , "+ zval chain %d: ref (%d) %p\n" , i , Z_REFCOUNT_P (var ), var );
596
+ #endif
597
+
598
+ }
599
+
600
+
546
601
static inline int php_add_var_hash (HashTable * var_hash , zval * var , void * var_old TSRMLS_DC ) /* {{{ */
547
602
{
548
603
ulong var_no ;
@@ -572,6 +627,9 @@ static inline int php_add_var_hash(HashTable *var_hash, zval *var, void *var_old
572
627
return FAILURE ;
573
628
}
574
629
630
+ // capture the zval to keep it alive for the duration of serialization
631
+ php_var_serialize_capture_zval (var );
632
+
575
633
/* +1 because otherwise hash will think we are trying to store NULL pointer */
576
634
var_no = zend_hash_num_elements (var_hash ) + 1 ;
577
635
zend_hash_add (var_hash , p , len , & var_no , sizeof (var_no ), NULL );
0 commit comments