Visitar URL original
Improve validation of UTF-8 encoded character literals (#221) · bavison/simplecpp@cce3632 · GitHub
Skip to content

Commit cce3632

Browse files
authored
Improve validation of UTF-8 encoded character literals (cppcheck-opensource#221)
1 parent f997119 commit cce3632

2 files changed

Lines changed: 25 additions & 4 deletions

File tree

‎simplecpp.cpp‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2486,16 +2486,17 @@ long long simplecpp::characterLiteralToLL(const std::string& str)
24862486

24872487
if (!narrow && value >= 0x80) {
24882488
// Assuming this is a UTF-8 encoded code point.
2489-
// This decoder does not completely validate the input, for example it doesn't reject overlong encodings.
2489+
// This decoder may not completely validate the input.
2490+
// Noncharacters are neither rejected nor replaced.
24902491

24912492
int additional_bytes;
2492-
if (value >= 0xf8)
2493+
if (value >= 0xf5) // higher values would result in code points above 0x10ffff
24932494
throw std::runtime_error("assumed UTF-8 encoded source, but sequence is invalid");
24942495
else if (value >= 0xf0)
24952496
additional_bytes = 3;
24962497
else if (value >= 0xe0)
24972498
additional_bytes = 2;
2498-
else if (value >= 0xc0)
2499+
else if (value >= 0xc2) // 0xc0 and 0xc1 are always overlong 2-bytes encodings
24992500
additional_bytes = 1;
25002501
else
25012502
throw std::runtime_error("assumed UTF-8 encoded source, but sequence is invalid");
@@ -2505,9 +2506,14 @@ long long simplecpp::characterLiteralToLL(const std::string& str)
25052506
while (additional_bytes--) {
25062507
if(pos + 1 >= str.size())
25072508
throw std::runtime_error("assumed UTF-8 encoded source, but character literal ends unexpectedly");
2509+
25082510
unsigned char c = str[pos++];
2509-
if((c >> 6) != 2) // ensure c has form 0xb10xxxxxx
2511+
2512+
if (((c >> 6) != 2) // ensure c has form 0xb10xxxxxx
2513+
|| (!value && additional_bytes == 1 && c < 0xa0) // overlong 3-bytes encoding
2514+
|| (!value && additional_bytes == 2 && c < 0x90)) // overlong 4-bytes encoding
25102515
throw std::runtime_error("assumed UTF-8 encoded source, but sequence is invalid");
2516+
25112517
value = (value << 6) | (c & ((1 << 7) - 1));
25122518
}
25132519

‎test.cpp‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,8 @@ static void characterLiteral()
263263
ASSERT_EQUALS('\x89', simplecpp::characterLiteralToLL("'\x89'"));
264264
ASSERT_THROW(simplecpp::characterLiteralToLL("U'\x89'"), std::runtime_error);
265265

266+
ASSERT_THROW(simplecpp::characterLiteralToLL("U'\xf4\x90\x80\x80'"), std::runtime_error);
267+
266268
// following examples based on https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
267269
ASSERT_EQUALS(0x80, simplecpp::characterLiteralToLL("U'\xc2\x80'"));
268270
ASSERT_EQUALS(0x800, simplecpp::characterLiteralToLL("U'\xe0\xa0\x80'"));
@@ -296,6 +298,19 @@ static void characterLiteral()
296298

297299
ASSERT_THROW(simplecpp::characterLiteralToLL("U'\xf8'"), std::runtime_error);
298300
ASSERT_THROW(simplecpp::characterLiteralToLL("U'\xff'"), std::runtime_error);
301+
302+
ASSERT_THROW(simplecpp::characterLiteralToLL("U'\xc0\xaf'"), std::runtime_error);
303+
ASSERT_THROW(simplecpp::characterLiteralToLL("U'\xe0\x80\xaf'"), std::runtime_error);
304+
ASSERT_THROW(simplecpp::characterLiteralToLL("U'\xf0\x80\x80\xaf'"), std::runtime_error);
305+
ASSERT_THROW(simplecpp::characterLiteralToLL("U'\xc1\xbf'"), std::runtime_error);
306+
ASSERT_THROW(simplecpp::characterLiteralToLL("U'\xe0\x9f\xbf'"), std::runtime_error);
307+
ASSERT_THROW(simplecpp::characterLiteralToLL("U'\xf0\x8f\xbf\xbf'"), std::runtime_error);
308+
ASSERT_THROW(simplecpp::characterLiteralToLL("U'\xc0\x80'"), std::runtime_error);
309+
ASSERT_THROW(simplecpp::characterLiteralToLL("U'\xe0\x80\x80'"), std::runtime_error);
310+
ASSERT_THROW(simplecpp::characterLiteralToLL("U'\xf0\x80\x80\x80'"), std::runtime_error);
311+
312+
ASSERT_THROW(simplecpp::characterLiteralToLL("U'\xed\xa0\x80'"), std::runtime_error);
313+
ASSERT_THROW(simplecpp::characterLiteralToLL("U'\xed\xbf\xbf'"), std::runtime_error);
299314
}
300315

301316
static void combineOperators_floatliteral()

0 commit comments

Comments
 (0)