@@ -32,27 +32,38 @@ extern "C" {
3232zend_class_entry *IntlIterator_ce_ptr;
3333zend_object_handlers IntlIterator_handlers;
3434
35+ static void zoi_with_current_destroy_self (zend_object_iterator *iter, zoi_with_current *zoiwc)
36+ {
37+ /* Object not here anymore (we've been called by the object free handler)
38+ * Note that the iterator wrapper objects (that also depend on this
39+ * structure) call this function earlier, in the destruction phase, which
40+ * precedes the object free phase. Therefore there's no risk on this
41+ * function being called by the iterator wrapper destructor function and
42+ * not finding the memory of this iterator allocated anymore. */
43+ iter->funcs ->invalidate_current (iter);
44+ zoiwc->destroy_it (iter);
45+ }
46+
3547void zoi_with_current_dtor (zend_object_iterator *iter)
3648{
3749 zoi_with_current *zoiwc = (zoi_with_current*)iter;
3850
3951 if (!Z_ISUNDEF (zoiwc->wrapping_obj )) {
4052 /* we have to copy the pointer because zoiwc->wrapping_obj may be
41- * changed midway the execution of zval_ptr_dtor() */
53+ * changed midway the execution of zval_ptr_dtor() */
4254 zval *zwo = &zoiwc->wrapping_obj ;
4355
4456 /* object is still here, we can rely on it to call this again and
4557 * destroy this object */
4658 zval_ptr_dtor (zwo);
59+
60+ /* We may only invalidate and destroy if this was actually the last instance.
61+ * If it was, then IntlIterator_objects_free() will have set zwo to UNDEF. */
62+ if (Z_ISUNDEF_P (zwo)) {
63+ zoi_with_current_destroy_self (iter, zoiwc);
64+ }
4765 } else {
48- /* Object not here anymore (we've been called by the object free handler)
49- * Note that the iterator wrapper objects (that also depend on this
50- * structure) call this function earlier, in the destruction phase, which
51- * precedes the object free phase. Therefore there's no risk on this
52- * function being called by the iterator wrapper destructor function and
53- * not finding the memory of this iterator allocated anymore. */
54- iter->funcs ->invalidate_current (iter);
55- zoiwc->destroy_it (iter);
66+ zoi_with_current_destroy_self (iter, zoiwc);
5667 }
5768}
5869
@@ -126,6 +137,16 @@ static void string_enum_destroy_it(zend_object_iterator *iter)
126137 delete (StringEnumeration*)Z_PTR (iter->data );
127138}
128139
140+ static HashTable *string_enum_get_gc (zend_object_iterator *object, zval **table, int *n)
141+ {
142+ zoi_with_current *zoiwc = (zoi_with_current *) object;
143+
144+ *table = &zoiwc->wrapping_obj ;
145+ *n = 1 ;
146+
147+ return NULL ;
148+ }
149+
129150static const zend_object_iterator_funcs string_enum_object_iterator_funcs = {
130151 zoi_with_current_dtor,
131152 zoi_with_current_valid,
@@ -134,7 +155,7 @@ static const zend_object_iterator_funcs string_enum_object_iterator_funcs = {
134155 string_enum_current_move_forward,
135156 string_enum_rewind,
136157 zoi_with_current_invalidate_current,
137- NULL , /* get_gc */
158+ string_enum_get_gc,
138159};
139160
140161U_CFUNC void IntlIterator_from_StringEnumeration (StringEnumeration *se, zval *object)
@@ -148,7 +169,8 @@ U_CFUNC void IntlIterator_from_StringEnumeration(StringEnumeration *se, zval *ob
148169 ii->iterator ->funcs = &string_enum_object_iterator_funcs;
149170 ii->iterator ->index = 0 ;
150171 ((zoi_with_current*)ii->iterator )->destroy_it = string_enum_destroy_it;
151- ZVAL_OBJ (&((zoi_with_current*)ii->iterator )->wrapping_obj , Z_OBJ_P (object));
172+ /* This iterator holds a reference to the object, the object may not disappear */
173+ ZVAL_OBJ_COPY (&((zoi_with_current*)ii->iterator )->wrapping_obj , Z_OBJ_P (object));
152174 ZVAL_UNDEF (&((zoi_with_current*)ii->iterator )->current );
153175}
154176
@@ -158,6 +180,7 @@ static void IntlIterator_objects_free(zend_object *object)
158180
159181 if (ii->iterator ) {
160182 zval *wrapping_objp = &((zoi_with_current*)ii->iterator )->wrapping_obj ;
183+ /* Signal that it was the last reference that got destroyed */
161184 ZVAL_UNDEF (wrapping_objp);
162185 zend_iterator_dtor (ii->iterator );
163186 }
@@ -166,6 +189,22 @@ static void IntlIterator_objects_free(zend_object *object)
166189 zend_object_std_dtor (&ii->zo );
167190}
168191
192+ static HashTable *IntlIterator_get_gc (zend_object *object, zval **table, int *n)
193+ {
194+ IntlIterator_object *ii = php_intl_iterator_fetch_object (object);
195+
196+ if (ii->iterator ) {
197+ zend_get_gc_buffer *gc = zend_get_gc_buffer_create ();
198+ zend_get_gc_buffer_add_obj (gc, &ii->iterator ->std );
199+ zend_get_gc_buffer_use (gc, table, n);
200+ } else {
201+ *table = NULL ;
202+ *n = 0 ;
203+ }
204+
205+ return NULL ;
206+ }
207+
169208static zend_object_iterator *IntlIterator_get_iterator (
170209 zend_class_entry *ce, zval *object, int by_ref)
171210{
@@ -298,5 +337,5 @@ U_CFUNC void intl_register_IntlIterator_class(void)
298337 IntlIterator_handlers.offset = XtOffsetOf (IntlIterator_object, zo);
299338 IntlIterator_handlers.clone_obj = NULL ;
300339 IntlIterator_handlers.free_obj = IntlIterator_objects_free;
301-
340+ IntlIterator_handlers. get_gc = IntlIterator_get_gc;
302341}
0 commit comments