Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: 870de4ab779eacbf74616853e81b66e9275b8fc1
https://github.com/WebKit/WebKit/commit/870de4ab779eacbf74616853e81b66e9275b8fc1
Author: Ahmad Saleem <[email protected]>
Date: 2026-08-16 (Sun, 16 Aug 2026)
Changed paths:
M Source/WTF/wtf/text/TextBreakIterator.cpp
M Source/WTF/wtf/text/TextBreakIterator.h
Log Message:
-----------
NonSharedCharacterBreakIterator and NonSharedSentenceBreakIterator leak their
UBreakIterator when setting the text fails
https://bugs.webkit.org/show_bug.cgi?id=321873
rdar://185053056
Reviewed by Chris Dumez.
Both constructors took ownership of a UBreakIterator from the one-entry cache
(or freshly ubrk_open()ed one) and then overwrote that pointer with the result
of setTextForIterator(), dropping the only reference to it when setting the
text failed:
if ((m_iterator = getNonSharedCharacterBreakIterator()))
m_iterator = setTextForIterator(*m_iterator, string);
Nothing else owns the iterator at that point, since getNonShared*() removes it
from the cache with an exchange(), so the iterator was leaked. This is
reachable: setTextForIterator() fails for a null StringView, because
openLatin1UTextProvider() rejects a null data pointer with
U_ILLEGAL_ARGUMENT_ERROR. StringView::GraphemeClusters guards against that case
already, but other callers do not.
Rather than adding a manual ubrk_close() on the failure path, make the
ownership explicit with the smart pointer WebKit already uses for ICU handles,
std::unique_ptr<T, ICUDeleter<close>>, so that the leak is not expressible:
getNonShared*BreakIterator() now returns ownership,
cacheNonShared*BreakIterator()
now takes it, and no function passes a raw owning UBreakIterator* around. This
also removes the manual ubrk_close() of the evicted cache entry and lets both
move constructors be defaulted. CheckedPtr and Ref are not applicable here:
UBreakIterator is an opaque ICU C type that can be neither CanMakeCheckedPtr
nor refcounted.
As a drive-by, setTextForIterator() skipped utext_close() when ubrk_setUText()
failed; use makeScopeExit() so it runs on every path out of the 8-bit branch.
No memory was leaked by this, because the UText is set up over a stack buffer,
but the provider's close hook was not being run.
* Source/WTF/wtf/text/TextBreakIterator.cpp:
(WTF::setTextForIterator):
(WTF::getNonSharedCharacterBreakIterator):
(WTF::cacheNonSharedCharacterBreakIterator):
(WTF::NonSharedCharacterBreakIterator::NonSharedCharacterBreakIterator):
(WTF::NonSharedCharacterBreakIterator::~NonSharedCharacterBreakIterator):
(WTF::getNonSharedSentenceBreakIterator):
(WTF::cacheNonSharedSentenceBreakIterator):
(WTF::NonSharedSentenceBreakIterator::NonSharedSentenceBreakIterator):
(WTF::NonSharedSentenceBreakIterator::~NonSharedSentenceBreakIterator):
* Source/WTF/wtf/text/TextBreakIterator.h:
(WTF::NonSharedCharacterBreakIterator::operator UBreakIterator* const):
(WTF::NonSharedSentenceBreakIterator::operator UBreakIterator* const):
Canonical link: https://commits.webkit.org/319266@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications