Index: lib/StaticAnalyzer/Core/CMakeLists.txt =================================================================== --- lib/StaticAnalyzer/Core/CMakeLists.txt +++ lib/StaticAnalyzer/Core/CMakeLists.txt @@ -53,6 +53,7 @@ clangAnalysis clangBasic clangCrossTU + clangFrontend clangLex clangRewrite ) Index: lib/StaticAnalyzer/Core/PlistDiagnostics.cpp =================================================================== --- lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -15,6 +15,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/Version.h" #include "clang/CrossTU/CrossTranslationUnit.h" +#include "clang/Frontend/ASTUnit.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/TokenConcatenation.h" #include "clang/Rewrite/Core/HTMLRewrite.h" @@ -75,12 +76,14 @@ const FIDMap& FM; AnalyzerOptions &AnOpts; const Preprocessor &PP; + const cross_tu::CrossTranslationUnitContext &CTU; llvm::SmallVector MacroPieces; public: PlistPrinter(const FIDMap& FM, AnalyzerOptions &AnOpts, - const Preprocessor &PP) - : FM(FM), AnOpts(AnOpts), PP(PP) { + const Preprocessor &PP, + const cross_tu::CrossTranslationUnitContext &CTU) + : FM(FM), AnOpts(AnOpts), PP(PP), CTU(CTU) { } void ReportDiag(raw_ostream &o, const PathDiagnosticPiece& P) { @@ -162,8 +165,8 @@ } // end of anonymous namespace static void printBugPath(llvm::raw_ostream &o, const FIDMap& FM, - AnalyzerOptions &AnOpts, - const Preprocessor &PP, + AnalyzerOptions &AnOpts, const Preprocessor &PP, + const cross_tu::CrossTranslationUnitContext &CTU, const PathPieces &Path); /// Print coverage information to output stream {@code o}. @@ -174,8 +177,9 @@ FIDMap &FM, llvm::raw_fd_ostream &o); -static ExpansionInfo getExpandedMacro(SourceLocation MacroLoc, - const Preprocessor &PP); +static ExpansionInfo +getExpandedMacro(SourceLocation MacroLoc, const Preprocessor &PP, + const cross_tu::CrossTranslationUnitContext &CTU); //===----------------------------------------------------------------------===// // Methods of PlistPrinter. @@ -349,7 +353,7 @@ for (const PathDiagnosticMacroPiece *P : MacroPieces) { const SourceManager &SM = PP.getSourceManager(); - ExpansionInfo EI = getExpandedMacro(P->getLocation().asLocation(), PP); + ExpansionInfo EI = getExpandedMacro(P->getLocation().asLocation(), PP, CTU); Indent(o, indent) << "\n"; ++indent; @@ -471,10 +475,10 @@ } static void printBugPath(llvm::raw_ostream &o, const FIDMap& FM, - AnalyzerOptions &AnOpts, - const Preprocessor &PP, + AnalyzerOptions &AnOpts, const Preprocessor &PP, + const cross_tu::CrossTranslationUnitContext &CTU, const PathPieces &Path) { - PlistPrinter Printer(FM, AnOpts, PP); + PlistPrinter Printer(FM, AnOpts, PP, CTU); assert(std::is_partitioned( Path.begin(), Path.end(), [](const std::shared_ptr &E) @@ -619,7 +623,7 @@ o << " \n"; const PathDiagnostic *D = *DI; - printBugPath(o, FM, AnOpts, PP, D->path); + printBugPath(o, FM, AnOpts, PP, CTU, D->path); // Output the bug type and bug category. o << " description"; @@ -872,17 +876,23 @@ // Definitions of helper functions and methods for expanding macros. //===----------------------------------------------------------------------===// -static ExpansionInfo getExpandedMacro(SourceLocation MacroLoc, - const Preprocessor &PP) { +static ExpansionInfo +getExpandedMacro(SourceLocation MacroLoc, const Preprocessor &PP, + const cross_tu::CrossTranslationUnitContext &CTU) { + + const Preprocessor *PPToUse = &PP; + if (auto LocAndUnit = CTU.getImportedFromSourceLocation(MacroLoc)) { + MacroLoc = LocAndUnit->first; + PPToUse = &LocAndUnit->second->getPreprocessor(); + } llvm::SmallString<200> ExpansionBuf; llvm::raw_svector_ostream OS(ExpansionBuf); - TokenPrinter Printer(OS, PP); + TokenPrinter Printer(OS, *PPToUse); llvm::SmallPtrSet AlreadyProcessedTokens; - std::string MacroName = - getMacroNameAndPrintExpansion(Printer, MacroLoc, PP, MacroArgMap{}, - AlreadyProcessedTokens); + std::string MacroName = getMacroNameAndPrintExpansion( + Printer, MacroLoc, *PPToUse, MacroArgMap{}, AlreadyProcessedTokens); return { MacroName, OS.str() }; } Index: test/Analysis/Inputs/plist-macros-ctu.h =================================================================== --- /dev/null +++ test/Analysis/Inputs/plist-macros-ctu.h @@ -0,0 +1,4 @@ +#define M_H *A = (int *)0 +void F_H(int **A) { + M_H; +} Index: test/Analysis/Inputs/plist-macros-ctu.c =================================================================== --- /dev/null +++ test/Analysis/Inputs/plist-macros-ctu.c @@ -0,0 +1,21 @@ + +#include "plist-macros-ctu.h" + +#define M *X = (int *)0 + +void F1(int **X) { + M; +} + +#undef M +#define M *Y = (int *)0 + +void F2(int **Y) { + M; +} + +#define M1 *Z = (int *)0 + +void F3(int **Z) { + M1; +} Index: test/Analysis/Inputs/plist-macros-with-expansion-ctu.c.externalDefMap.txt =================================================================== --- /dev/null +++ test/Analysis/Inputs/plist-macros-with-expansion-ctu.c.externalDefMap.txt @@ -0,0 +1,4 @@ +c:@F@F1 plist-macros-ctu.c.ast +c:@F@F2 plist-macros-ctu.c.ast +c:@F@F3 plist-macros-ctu.c.ast +c:@F@F_H plist-macros-ctu.c.ast Index: test/Analysis/plist-macros-with-expansion-ctu.c =================================================================== --- /dev/null +++ test/Analysis/plist-macros-with-expansion-ctu.c @@ -0,0 +1,80 @@ +// RUN: rm -rf %t && mkdir %t +// RUN: mkdir -p %t/ctudir +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu \ +// RUN: -emit-pch -o %t/ctudir/plist-macros-ctu.c.ast %S/Inputs/plist-macros-ctu.c +// RUN: cp %S/Inputs/plist-macros-with-expansion-ctu.c.externalDefMap.txt %t/ctudir/externalDefMap.txt + +// RUN: %clang_analyze_cc1 -analyzer-checker=core \ +// RUN: -analyzer-config experimental-enable-naive-ctu-analysis=true \ +// RUN: -analyzer-config ctu-dir=%t/ctudir \ +// RUN: -analyzer-config expand-macros=true \ +// RUN: -analyzer-output=plist-multi-file -o %t.plist -verify %s + +// Check the macro expansions from the plist output here, to make the test more +// understandable. +// RUN: FileCheck --input-file=%t.plist %s + +extern void F1(int **); +extern void F2(int **); +extern void F3(int **); +extern void F_H(int **); + +void test0() { + int *X; + F3(&X); + *X = 1; // expected-warning{{Dereference of null pointer}} +} +// CHECK: nameM1 +// CHECK-NEXT: expansion*Z = (int *)0 + + +void test1() { + int *X; + F1(&X); + *X = 1; // expected-warning{{Dereference of null pointer}} +} +// CHECK: nameM +// CHECK-NEXT: expansion*X = (int *)0 + +void test2() { + int *X; + F2(&X); + *X = 1; // expected-warning{{Dereference of null pointer}} +} +// CHECK: nameM +// CHECK-NEXT: expansion*Y = (int *)0 + +#define M F1(&X) + +void test3() { + int *X; + M; + *X = 1; // expected-warning{{Dereference of null pointer}} +} +// CHECK: nameM +// CHECK-NEXT: expansionF1(&X) +// CHECK: nameM +// CHECK-NEXT: expansion*X = (int *)0 + +#undef M +#define M F2(&X) + +void test4() { + int *X; + M; + *X = 1; // expected-warning{{Dereference of null pointer}} +} + +// CHECK: nameM +// CHECK-NEXT: expansionF2(&X) +// CHECK: nameM +// CHECK-NEXT: expansion*Y = (int *)0 + +void test_h() { + int *X; + F_H(&X); + *X = 1; // expected-warning{{Dereference of null pointer}} +} + +// CHECK: nameM_H +// CHECK-NEXT: expansion*A = (int *)0