Skip to content

Commit 209e0d6

Browse files
committed
Merge branch 'PHP-8.4'
* PHP-8.4: Fix GH-11874: intl causing segfault in docker images
2 parents 8a0b617 + 0ee6691 commit 209e0d6

File tree

3 files changed

+46
-25
lines changed

3 files changed

+46
-25
lines changed

ext/intl/breakiterator/breakiterator_iterators.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ inline BreakIterator *_breakiter_prolog(zend_object_iterator *iter)
5151
static void _breakiterator_destroy_it(zend_object_iterator *iter)
5252
{
5353
zval_ptr_dtor(&iter->data);
54+
/* Don't free iter here because it is allocated as an object on its own, not embedded. */
5455
}
5556

5657
static void _breakiterator_move_forward(zend_object_iterator *iter)
@@ -79,8 +80,18 @@ static void _breakiterator_rewind(zend_object_iterator *iter)
7980
ZVAL_LONG(&zoi_iter->current, (zend_long)pos);
8081
}
8182

83+
static void zoi_with_current_dtor_self(zend_object_iterator *iter)
84+
{
85+
// Note: wrapping_obj is unused, call to zoi_with_current_dtor() not necessary
86+
zoi_with_current *zoi_iter = (zoi_with_current*)iter;
87+
ZEND_ASSERT(Z_ISUNDEF(zoi_iter->wrapping_obj));
88+
89+
// Unlike the other iterators, this iterator is a new, standalone instance
90+
zoi_iter->destroy_it(iter);
91+
}
92+
8293
static const zend_object_iterator_funcs breakiterator_iterator_funcs = {
83-
zoi_with_current_dtor,
94+
zoi_with_current_dtor_self,
8495
zoi_with_current_valid,
8596
zoi_with_current_get_current_data,
8697
NULL,
@@ -133,6 +144,7 @@ typedef struct zoi_break_iter_parts {
133144
static void _breakiterator_parts_destroy_it(zend_object_iterator *iter)
134145
{
135146
zval_ptr_dtor(&iter->data);
147+
efree(iter);
136148
}
137149

138150
static void _breakiterator_parts_get_current_key(zend_object_iterator *iter, zval *key)
@@ -231,7 +243,7 @@ void IntlIterator_from_BreakIterator_parts(zval *break_iter_zv,
231243
ii->iterator->index = 0;
232244

233245
((zoi_with_current*)ii->iterator)->destroy_it = _breakiterator_parts_destroy_it;
234-
ZVAL_OBJ(&((zoi_with_current*)ii->iterator)->wrapping_obj, Z_OBJ_P(object));
246+
ZVAL_OBJ_COPY(&((zoi_with_current*)ii->iterator)->wrapping_obj, Z_OBJ_P(object));
235247
ZVAL_UNDEF(&((zoi_with_current*)ii->iterator)->current);
236248

237249
((zoi_break_iter_parts*)ii->iterator)->bio = Z_INTL_BREAKITERATOR_P(break_iter_zv);

ext/intl/common/common_enum.cpp

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -35,25 +35,7 @@ zend_object_handlers IntlIterator_handlers;
3535
void zoi_with_current_dtor(zend_object_iterator *iter)
3636
{
3737
zoi_with_current *zoiwc = (zoi_with_current*)iter;
38-
39-
if (!Z_ISUNDEF(zoiwc->wrapping_obj)) {
40-
/* we have to copy the pointer because zoiwc->wrapping_obj may be
41-
* changed midway the execution of zval_ptr_dtor() */
42-
zval *zwo = &zoiwc->wrapping_obj;
43-
44-
/* object is still here, we can rely on it to call this again and
45-
* destroy this object */
46-
zval_ptr_dtor(zwo);
47-
} 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);
56-
}
38+
zval_ptr_dtor(&zoiwc->wrapping_obj);
5739
}
5840

5941
U_CFUNC zend_result zoi_with_current_valid(zend_object_iterator *iter)
@@ -124,6 +106,7 @@ static void string_enum_rewind(zend_object_iterator *iter)
124106
static void string_enum_destroy_it(zend_object_iterator *iter)
125107
{
126108
delete (StringEnumeration*)Z_PTR(iter->data);
109+
efree(iter);
127110
}
128111

129112
static const zend_object_iterator_funcs string_enum_object_iterator_funcs = {
@@ -148,7 +131,7 @@ U_CFUNC void IntlIterator_from_StringEnumeration(StringEnumeration *se, zval *ob
148131
ii->iterator->funcs = &string_enum_object_iterator_funcs;
149132
ii->iterator->index = 0;
150133
((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));
134+
ZVAL_OBJ_COPY(&((zoi_with_current*)ii->iterator)->wrapping_obj, Z_OBJ_P(object));
152135
ZVAL_UNDEF(&((zoi_with_current*)ii->iterator)->current);
153136
}
154137

@@ -157,9 +140,7 @@ static void IntlIterator_objects_free(zend_object *object)
157140
IntlIterator_object *ii = php_intl_iterator_fetch_object(object);
158141

159142
if (ii->iterator) {
160-
zval *wrapping_objp = &((zoi_with_current*)ii->iterator)->wrapping_obj;
161-
ZVAL_UNDEF(wrapping_objp);
162-
zend_iterator_dtor(ii->iterator);
143+
((zoi_with_current*)ii->iterator)->destroy_it(ii->iterator);
163144
}
164145
intl_error_reset(INTLITERATOR_ERROR_P(ii));
165146

ext/intl/tests/gh11874.phpt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
GH-11874 (intl causing segfault in docker images)
3+
--EXTENSIONS--
4+
intl
5+
--FILE--
6+
<?php
7+
8+
foreach(IntlCalendar::getKeywordValuesForLocale('calendar', 'fa_IR', true) as $id) {
9+
var_dump($id);
10+
}
11+
12+
$result = '';
13+
foreach(IntlTimeZone::createTimeZoneIDEnumeration(IntlTimeZone::TYPE_ANY) as $id) {
14+
$result .= $id;
15+
}
16+
17+
var_dump(strlen($result) > 0);
18+
echo "No crash\n";
19+
20+
?>
21+
--EXPECT--
22+
string(7) "persian"
23+
string(9) "gregorian"
24+
string(7) "islamic"
25+
string(13) "islamic-civil"
26+
string(12) "islamic-tbla"
27+
bool(true)
28+
No crash

0 commit comments

Comments
 (0)