Ver Fonte

Fixed a crash on replaying Preamble's PP conditional stack.

Summary:
The crash occurs when the first token after a preamble is a macro
expansion.
Fixed by moving replayPreambleConditionalStack from Parser into
Preprocessor. It is now called right after the predefines file is
processed.

Reviewers: erikjv, bkramer, klimek, yvvan

Reviewed By: bkramer

Subscribers: cfe-commits

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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@311330 91177308-0d34-0410-b5e6-96231b3b80d8
Ilya Biryukov há 8 anos atrás
pai
commit
0d2d302e54

+ 4 - 4
include/clang/Lex/Preprocessor.h

@@ -1049,10 +1049,6 @@ public:
   /// which implicitly adds the builtin defines etc.
   /// which implicitly adds the builtin defines etc.
   void EnterMainSourceFile();
   void EnterMainSourceFile();
 
 
-  /// \brief After parser warm-up, initialize the conditional stack from
-  /// the preamble.
-  void replayPreambleConditionalStack();
-
   /// \brief Inform the preprocessor callbacks that processing is complete.
   /// \brief Inform the preprocessor callbacks that processing is complete.
   void EndSourceFile();
   void EndSourceFile();
 
 
@@ -2026,6 +2022,10 @@ public:
   }
   }
 
 
 private:
 private:
+  /// \brief After processing predefined file, initialize the conditional stack from
+  /// the preamble.
+  void replayPreambleConditionalStack();
+
   // Macro handling.
   // Macro handling.
   void HandleDefineDirective(Token &Tok, bool ImmediatelyAfterTopLevelIfndef);
   void HandleDefineDirective(Token &Tok, bool ImmediatelyAfterTopLevelIfndef);
   void HandleUndefDirective();
   void HandleUndefDirective();

+ 12 - 1
lib/Lex/PPLexerChange.cpp

@@ -458,10 +458,16 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
       SourceMgr.setNumCreatedFIDsForFileID(CurPPLexer->getFileID(), NumFIDs);
       SourceMgr.setNumCreatedFIDsForFileID(CurPPLexer->getFileID(), NumFIDs);
     }
     }
 
 
+    bool ExitedFromPredefinesFile = false;
     FileID ExitedFID;
     FileID ExitedFID;
-    if (Callbacks && !isEndOfMacro && CurPPLexer)
+    if (!isEndOfMacro && CurPPLexer) {
       ExitedFID = CurPPLexer->getFileID();
       ExitedFID = CurPPLexer->getFileID();
 
 
+      assert(PredefinesFileID.isValid() &&
+             "HandleEndOfFile is called before PredefinesFileId is set");
+      ExitedFromPredefinesFile = (PredefinesFileID == ExitedFID);
+    }
+
     if (LeavingSubmodule) {
     if (LeavingSubmodule) {
       // We're done with this submodule.
       // We're done with this submodule.
       Module *M = LeaveSubmodule(/*ForPragma*/false);
       Module *M = LeaveSubmodule(/*ForPragma*/false);
@@ -489,6 +495,11 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
                              PPCallbacks::ExitFile, FileType, ExitedFID);
                              PPCallbacks::ExitFile, FileType, ExitedFID);
     }
     }
 
 
+    // Restore conditional stack from the preamble right after exiting from the
+    // predefines file.
+    if (ExitedFromPredefinesFile)
+      replayPreambleConditionalStack();
+
     // Client should lex another token unless we generated an EOM.
     // Client should lex another token unless we generated an EOM.
     return LeavingSubmodule;
     return LeavingSubmodule;
   }
   }

+ 2 - 0
lib/Lex/Preprocessor.cpp

@@ -540,6 +540,8 @@ void Preprocessor::EnterMainSourceFile() {
 void Preprocessor::replayPreambleConditionalStack() {
 void Preprocessor::replayPreambleConditionalStack() {
   // Restore the conditional stack from the preamble, if there is one.
   // Restore the conditional stack from the preamble, if there is one.
   if (PreambleConditionalStack.isReplaying()) {
   if (PreambleConditionalStack.isReplaying()) {
+    assert(CurPPLexer &&
+           "CurPPLexer is null when calling replayPreambleConditionalStack.");
     CurPPLexer->setConditionalLevels(PreambleConditionalStack.getStack());
     CurPPLexer->setConditionalLevels(PreambleConditionalStack.getStack());
     PreambleConditionalStack.doneReplaying();
     PreambleConditionalStack.doneReplaying();
   }
   }

+ 0 - 2
lib/Parse/Parser.cpp

@@ -516,8 +516,6 @@ void Parser::Initialize() {
 
 
   // Prime the lexer look-ahead.
   // Prime the lexer look-ahead.
   ConsumeToken();
   ConsumeToken();
-
-  PP.replayPreambleConditionalStack();
 }
 }
 
 
 void Parser::LateTemplateParserCleanupCallback(void *P) {
 void Parser::LateTemplateParserCleanupCallback(void *P) {

+ 12 - 0
test/Index/preamble-conditionals-crash.cpp

@@ -0,0 +1,12 @@
+#ifndef HEADER_GUARD
+
+#define FOO int aba;
+FOO
+
+#endif
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 \
+// RUN:                                       local -std=c++14 %s 2>&1 \
+// RUN: | FileCheck %s --implicit-check-not "libclang: crash detected" \
+// RUN:                --implicit-check-not "error:"
+// CHECK: macro expansion=FOO:3:9 Extent=[4:1 - 4:4]
+// CHECK: VarDecl=aba:4:1 (Definition) Extent=[4:1 - 4:4]

+ 8 - 0
test/Index/preamble-conditionals.cpp

@@ -0,0 +1,8 @@
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source local %s 2>&1 \
+// RUN: | FileCheck %s --implicit-check-not "error:"
+#ifndef FOO_H
+#define FOO_H
+
+void foo();
+
+#endif