]> granicus.if.org Git - clang/commitdiff
[Lex] Avoid out-of-bounds dereference in LexAngledStringLiteral.
authorVolodymyr Sapsai <vsapsai@apple.com>
Fri, 12 Jan 2018 18:54:35 +0000 (18:54 +0000)
committerVolodymyr Sapsai <vsapsai@apple.com>
Fri, 12 Jan 2018 18:54:35 +0000 (18:54 +0000)
Fix makes the loop in LexAngledStringLiteral more like the loops in
LexStringLiteral, LexCharConstant. When we skip a character after
backslash, we need to check if we reached the end of the file instead of
reading the next character unconditionally.

Discovered by OSS-Fuzz:
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=3832

rdar://problem/35572754

Reviewers: arphaman, kcc, rsmith, dexonsmith

Reviewed By: rsmith, dexonsmith

Subscribers: cfe-commits, rsmith, dexonsmith

Differential Revision: https://reviews.llvm.org/D41423

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@322390 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Lex/Lexer.cpp
test/Lexer/null-character-in-literal.c [new file with mode: 0644]
unittests/Lex/LexerTest.cpp

index 830354ab23f0d73a04b47ce7ccf0974d9480c541..8bd4ab0ff9caf2b74e0e7ac76033f8dac1733027 100644 (file)
@@ -2009,18 +2009,21 @@ bool Lexer::LexAngledStringLiteral(Token &Result, const char *CurPtr) {
   const char *AfterLessPos = CurPtr;
   char C = getAndAdvanceChar(CurPtr, Result);
   while (C != '>') {
-    // Skip escaped characters.
-    if (C == '\\' && CurPtr < BufferEnd) {
-      // Skip the escaped character.
-      getAndAdvanceChar(CurPtr, Result);
-    } else if (C == '\n' || C == '\r' ||             // Newline.
-               (C == 0 && (CurPtr-1 == BufferEnd ||  // End of file.
-                           isCodeCompletionPoint(CurPtr-1)))) {
+    // Skip escaped characters.  Escaped newlines will already be processed by
+    // getAndAdvanceChar.
+    if (C == '\\')
+      C = getAndAdvanceChar(CurPtr, Result);
+
+    if (C == '\n' || C == '\r' ||             // Newline.
+        (C == 0 && (CurPtr-1 == BufferEnd ||  // End of file.
+                    isCodeCompletionPoint(CurPtr-1)))) {
       // If the filename is unterminated, then it must just be a lone <
       // character.  Return this as such.
       FormTokenWithChars(Result, AfterLessPos, tok::less);
       return true;
-    } else if (C == 0) {
+    }
+
+    if (C == 0) {
       NulCharacter = CurPtr-1;
     }
     C = getAndAdvanceChar(CurPtr, Result);
diff --git a/test/Lexer/null-character-in-literal.c b/test/Lexer/null-character-in-literal.c
new file mode 100644 (file)
index 0000000..a479547
Binary files /dev/null and b/test/Lexer/null-character-in-literal.c differ
index 746d08a43eaf2e53f84e75d393cd0548b7b9681b..216672a90d5efcab883d5cb9e86f7701679a9389 100644 (file)
@@ -475,6 +475,8 @@ TEST_F(LexerTest, GetBeginningOfTokenWithEscapedNewLine) {
 
 TEST_F(LexerTest, AvoidPastEndOfStringDereference) {
   EXPECT_TRUE(Lex("  //  \\\n").empty());
+  EXPECT_TRUE(Lex("#include <\\\\").empty());
+  EXPECT_TRUE(Lex("#include <\\\\\n").empty());
 }
 
 TEST_F(LexerTest, StringizingRasString) {