Skip to content

Fix GH-11874: intl causing segfault in docker images #17343

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions ext/intl/breakiterator/breakiterator_iterators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ inline BreakIterator *_breakiter_prolog(zend_object_iterator *iter)
static void _breakiterator_destroy_it(zend_object_iterator *iter)
{
zval_ptr_dtor(&iter->data);
/* Don't free iter here because it is allocated as an object on its own, not embedded. */
}

static void _breakiterator_move_forward(zend_object_iterator *iter)
Expand Down Expand Up @@ -79,8 +80,18 @@ static void _breakiterator_rewind(zend_object_iterator *iter)
ZVAL_LONG(&zoi_iter->current, (zend_long)pos);
}

static void zoi_with_current_dtor_self(zend_object_iterator *iter)
{
// Note: wrapping_obj is unused, call to zoi_with_current_dtor() not necessary
zoi_with_current *zoi_iter = (zoi_with_current*)iter;
ZEND_ASSERT(Z_ISUNDEF(zoi_iter->wrapping_obj));

// Unlike the other iterators, this iterator is a new, stadalone instance
zoi_iter->destroy_it(iter);
}

static const zend_object_iterator_funcs breakiterator_iterator_funcs = {
zoi_with_current_dtor,
zoi_with_current_dtor_self,
zoi_with_current_valid,
zoi_with_current_get_current_data,
NULL,
Expand Down Expand Up @@ -133,6 +144,7 @@ typedef struct zoi_break_iter_parts {
static void _breakiterator_parts_destroy_it(zend_object_iterator *iter)
{
zval_ptr_dtor(&iter->data);
efree(iter);
}

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

((zoi_with_current*)ii->iterator)->destroy_it = _breakiterator_parts_destroy_it;
ZVAL_OBJ(&((zoi_with_current*)ii->iterator)->wrapping_obj, Z_OBJ_P(object));
ZVAL_OBJ_COPY(&((zoi_with_current*)ii->iterator)->wrapping_obj, Z_OBJ_P(object));
ZVAL_UNDEF(&((zoi_with_current*)ii->iterator)->current);

((zoi_break_iter_parts*)ii->iterator)->bio = Z_INTL_BREAKITERATOR_P(break_iter_zv);
Expand Down
27 changes: 4 additions & 23 deletions ext/intl/common/common_enum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,25 +35,7 @@ zend_object_handlers IntlIterator_handlers;
void zoi_with_current_dtor(zend_object_iterator *iter)
{
zoi_with_current *zoiwc = (zoi_with_current*)iter;

if (!Z_ISUNDEF(zoiwc->wrapping_obj)) {
/* we have to copy the pointer because zoiwc->wrapping_obj may be
* changed midway the execution of zval_ptr_dtor() */
zval *zwo = &zoiwc->wrapping_obj;

/* object is still here, we can rely on it to call this again and
* destroy this object */
zval_ptr_dtor(zwo);
} else {
/* Object not here anymore (we've been called by the object free handler)
* Note that the iterator wrapper objects (that also depend on this
* structure) call this function earlier, in the destruction phase, which
* precedes the object free phase. Therefore there's no risk on this
* function being called by the iterator wrapper destructor function and
* not finding the memory of this iterator allocated anymore. */
iter->funcs->invalidate_current(iter);
zoiwc->destroy_it(iter);
}
zval_ptr_dtor(&zoiwc->wrapping_obj);
}

U_CFUNC int zoi_with_current_valid(zend_object_iterator *iter)
Expand Down Expand Up @@ -124,6 +106,7 @@ static void string_enum_rewind(zend_object_iterator *iter)
static void string_enum_destroy_it(zend_object_iterator *iter)
{
delete (StringEnumeration*)Z_PTR(iter->data);
efree(iter);
}

static const zend_object_iterator_funcs string_enum_object_iterator_funcs = {
Expand All @@ -148,7 +131,7 @@ U_CFUNC void IntlIterator_from_StringEnumeration(StringEnumeration *se, zval *ob
ii->iterator->funcs = &string_enum_object_iterator_funcs;
ii->iterator->index = 0;
((zoi_with_current*)ii->iterator)->destroy_it = string_enum_destroy_it;
ZVAL_OBJ(&((zoi_with_current*)ii->iterator)->wrapping_obj, Z_OBJ_P(object));
ZVAL_OBJ_COPY(&((zoi_with_current*)ii->iterator)->wrapping_obj, Z_OBJ_P(object));
ZVAL_UNDEF(&((zoi_with_current*)ii->iterator)->current);
}

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

if (ii->iterator) {
zval *wrapping_objp = &((zoi_with_current*)ii->iterator)->wrapping_obj;
ZVAL_UNDEF(wrapping_objp);
zend_iterator_dtor(ii->iterator);
((zoi_with_current*)ii->iterator)->destroy_it(ii->iterator);
}
intl_error_reset(INTLITERATOR_ERROR_P(ii));

Expand Down
28 changes: 28 additions & 0 deletions ext/intl/tests/gh11874.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
--TEST--
GH-11874 (intl causing segfault in docker images)
--EXTENSIONS--
intl
--FILE--
<?php

foreach(IntlCalendar::getKeywordValuesForLocale('calendar', 'fa_IR', true) as $id) {
var_dump($id);
}

$result = '';
foreach(IntlTimeZone::createTimeZoneIDEnumeration(IntlTimeZone::TYPE_ANY) as $id) {
$result .= $id;
}

var_dump(strlen($result) > 0);
echo "No crash\n";

?>
--EXPECT--
string(7) "persian"
string(9) "gregorian"
string(7) "islamic"
string(13) "islamic-civil"
string(12) "islamic-tbla"
bool(true)
No crash
Loading