Skip to content
Merged
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
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ PHP NEWS
results. (iliaal)
. Fixed a leak in Locale::getKeywords() when a keyword value cannot be
read. (iliaal)
. Fixed a use-after-free when IntlRuleBasedBreakIterator is constructed
from compiled rules. (iliaal)

- PDO_PGSQL:
. Added Pdo\Pgsql::ATTR_CHUNK_SIZE to fetch a result set in chunks of the
Expand Down
8 changes: 8 additions & 0 deletions ext/intl/breakiterator/breakiterator_class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ static zend_object *BreakIterator_clone_obj(zend_object *object)
} else {
bio_new->biter = new_biter;
ZVAL_COPY(&bio_new->text, &bio_orig->text);
if (bio_orig->compiled_rules) {
bio_new->compiled_rules = zend_string_copy(bio_orig->compiled_rules);
}
}
} else {
zend_throw_error(NULL, "Cannot clone uninitialized BreakIterator");
Expand Down Expand Up @@ -163,6 +166,7 @@ static void breakiterator_object_init(BreakIterator_object *bio)
{
intl_error_init(BREAKITER_ERROR_P(bio));
bio->biter = NULL;
bio->compiled_rules = NULL;
ZVAL_UNDEF(&bio->text);
}
/* }}} */
Expand All @@ -177,6 +181,10 @@ static void BreakIterator_objects_free(zend_object *object)
delete bio->biter;
bio->biter = NULL;
}
if (bio->compiled_rules) {
zend_string_release(bio->compiled_rules);
bio->compiled_rules = NULL;
}
intl_error_reset(BREAKITER_ERROR_P(bio));

zend_object_std_dtor(&bio->zo);
Expand Down
2 changes: 2 additions & 0 deletions ext/intl/breakiterator/breakiterator_class.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ typedef struct {
// current text
zval text;

zend_string *compiled_rules;

zend_object zo;
} BreakIterator_object;

Expand Down
3 changes: 3 additions & 0 deletions ext/intl/breakiterator/rulebasedbreakiterator_methods.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ U_CFUNC PHP_METHOD(IntlRuleBasedBreakIterator, __construct)
}

breakiterator_object_create(object, rbbi, false);
if (compiled) {
Z_INTL_BREAKITERATOR_P(object)->compiled_rules = zend_string_copy(rules);
}
}

U_CFUNC PHP_METHOD(IntlRuleBasedBreakIterator, getRules)
Expand Down
77 changes: 77 additions & 0 deletions ext/intl/tests/rbbiter_compiled_rules_lifetime.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
--TEST--
IntlRuleBasedBreakIterator compiled rules outlive the source string
--EXTENSIONS--
intl
--SKIPIF--
<?php if (version_compare(INTL_ICU_VERSION, '68.1') < 0) die('skip for ICU >= 68.1'); ?>
--FILE--
<?php

$rules = <<<RULES
\$LN = [[:letter:] [:number:]];
\$S = [.;,:];

!!forward;
\$LN+ {1};
\$S+ {42};
!!reverse;
\$LN+ {1};
\$S+ {42};
!!safe_forward;
!!safe_reverse;
RULES;

$src = new IntlRuleBasedBreakIterator($rules);
$len = strlen($src->getBinaryRules());

$it = new IntlRuleBasedBreakIterator($src->getBinaryRules(), true);
unset($src);

/* ICU aliases the buffer it was built from, so the freed rules have to be
reclaimed and overwritten for the iterator below to read stale bytes. */
$ballast = [];
for ($i = 0; $i < 16; $i++) {
$ballast[] = str_repeat("\xCC", $len);
}

$it->setText('ab,cd');
echo $it->first(), "\n";
while (true) {
$n = $it->next();
if ($n === IntlBreakIterator::DONE) {
break;
}
echo $n, "\n";
}

$clone = clone $it;
unset($it);
$ballast[] = str_repeat("\xDD", $len);
$clone->setText('xy');
echo $clone->first(), "\n";
echo $clone->next(), "\n";

$src = new IntlRuleBasedBreakIterator($rules);
$it = new IntlRuleBasedBreakIterator($src->getBinaryRules(), true);
unset($src);
for ($i = 0; $i < 16; $i++) {
$ballast[] = str_repeat("\xEE", $len);
}
$it->setText('ab,cd');
$parts = $it->getPartsIterator();
unset($it);
foreach ($parts as $p) {
echo $p, "\n";
}

?>
--EXPECT--
0
2
3
5
0
2
ab
,
cd