diff --git a/folly/String-inl.h b/folly/String-inl.h index b5021d8679d..caa3cc5b71e 100644 --- a/folly/String-inl.h +++ b/folly/String-inl.h @@ -118,7 +118,9 @@ void cUnescape(StringPiece str, String& out, bool strict) { last = p; } else if (e == 'X') { // hex ++p; - if (p == str.end()) { // \x at end of string + if (p == str.end() || + detail::hexTable[static_cast(*p)] >= 16) { + // \x not followed by a hex digit if (strict) { throw_exception( "incomplete hex escape sequence"); diff --git a/folly/test/StringTest.cpp b/folly/test/StringTest.cpp index cdbf8d36f3b..993314cb6de 100644 --- a/folly/test/StringTest.cpp +++ b/folly/test/StringTest.cpp @@ -378,6 +378,18 @@ TEST(Escape, cUnescape) { cUnescape("hello\\q"), std::invalid_argument, "invalid escape sequence"); + + // \x must be followed by at least one hex digit, also before other text. + EXPECT_THROW_RE( + cUnescape("hello\\xg"), + std::invalid_argument, + "incomplete hex escape sequence"); + EXPECT_THROW_RE( + cUnescape("\\x\\n"), + std::invalid_argument, + "incomplete hex escape sequence"); + EXPECT_EQ("hello\\xg", cUnescape("hello\\xg", false)); + EXPECT_EQ("\\x\n", cUnescape("\\x\\n", false)); } TEST(Escape, uriEscape) {