Skip to content
Open
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
10 changes: 7 additions & 3 deletions src/ccutil/unichar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,12 +223,16 @@ std::vector<char32> UNICHAR::UTF8ToUTF32(const char *utf8_str) {
unicodes.reserve(utf8_length);
const_iterator end_it(end(utf8_str, utf8_length));
for (const_iterator it(begin(utf8_str, utf8_length)); it != end_it; ++it) {
if (it.is_legal()) {
unicodes.push_back(*it);
} else {
// utf8_step() reports the width from the leading byte alone; reject a
// truncated trailing sequence rather than let the iterator run past the
// end of the string (issue #4495).
const int remaining = end_it.utf8_data() - it.utf8_data();
const int step = utf8_step(it.utf8_data());
if (step <= 0 || step > remaining) {
unicodes.clear();
return unicodes;
}
unicodes.push_back(*it);
}
return unicodes;
}
Expand Down
19 changes: 19 additions & 0 deletions unittest/unichar_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,23 @@ TEST(UnicharTest, InvalidText) {
EXPECT_TRUE(utf8.empty());
}

TEST(UnicharTest, TruncatedUtf8) {
// This test verifies that UTF8ToUTF32 does not read past the end of a
// string that ends with a truncated multibyte prefix (issue #4495).
// A truncated multibyte prefix is invalid UTF-8, so the conversion
// must return an empty vector instead of reading past the NUL.
// Keep the explicit NULs to make the truncation boundary visible in each
// fixture; without them, the literal terminator is implicit.
const char *kTruncated2 = "\xC2\0";
const char *kTruncated3 = "\xE8\0";
const char *kTruncated4 = "\xF0\0";
const char *kTruncatedMid = "ab\xE8\0";
const char *kIllegalLeading = "\x80\0";
Comment thread
SomSamantray marked this conversation as resolved.
EXPECT_TRUE(UNICHAR::UTF8ToUTF32(kTruncated2).empty());
EXPECT_TRUE(UNICHAR::UTF8ToUTF32(kTruncated3).empty());
EXPECT_TRUE(UNICHAR::UTF8ToUTF32(kTruncated4).empty());
EXPECT_TRUE(UNICHAR::UTF8ToUTF32(kTruncatedMid).empty());
EXPECT_TRUE(UNICHAR::UTF8ToUTF32(kIllegalLeading).empty());
}

} // namespace tesseract
Loading