Index: lib/StaticAnalyzer/Core/BugReporterVisitors.cpp =================================================================== --- lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -160,6 +160,27 @@ return std::move(P); } +/// \return name of the macro inside the location \p Loc. +static StringRef getMacroName(SourceLocation Loc, + BugReporterContext &BRC) { + return Lexer::getImmediateMacroName( + Loc, + BRC.getSourceManager(), + BRC.getASTContext().getLangOpts()); +} + +/// \return Whether given spelling location corresponds to an expansion +/// of a function-like macro. +static bool isFunctionMacroExpansion(SourceLocation Loc, + const SourceManager &SM) { + if (!Loc.isMacroID()) + return false; + std::pair TLInfo = SM.getDecomposedLoc(Loc); + SrcMgr::SLocEntry SE = SM.getSLocEntry(TLInfo.first); + const SrcMgr::ExpansionInfo &EInfo = SE.getExpansion(); + return EInfo.isFunctionMacroExpansion(); +} + namespace { /// Put a diagnostic on return statement of all inlined functions @@ -377,9 +398,83 @@ } }; -} // namespace +} // end anonymous namespace namespace { + +class MacroNullReturnSuppressionVisitor final : + public BugReporterVisitorImpl { + + const SubRegion *RegionOfInterest; + +public: + MacroNullReturnSuppressionVisitor(const SubRegion *R) : RegionOfInterest(R) {} + + + static void *getTag() { + static int Tag = 0; + return static_cast(&Tag); + } + + void Profile(llvm::FoldingSetNodeID &ID) const override { + ID.AddPointer(getTag()); + } + + std::shared_ptr VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) override { + auto BugPoint = BR.getErrorNode()->getLocation().getAs(); + + if (!BugPoint) + return nullptr; + + std::string MacroName; + const SourceManager &SMgr = BRC.getSourceManager(); + if (auto Loc = matchAssignment(N, BRC)) { + if (isFunctionMacroExpansion(*Loc, SMgr)) { + std::string MacroName = getMacroName(*Loc, BRC); + SourceLocation BugLoc = BugPoint->getStmt()->getLocStart(); + if (!BugLoc.isMacroID() || + getMacroName(BugLoc, BRC) != MacroName) { + + BR.markInvalid(getTag(), MacroName.c_str()); + } + } + } + return nullptr; + } + +private: + /// \return Source location of right hand side of an assignment + /// into \c RegionOfInterest, empty optional if none found. + Optional matchAssignment(const ExplodedNode *N, + BugReporterContext &BRC) { + const Stmt *S = PathDiagnosticLocation::getStmt(N); + ProgramStateRef State = N->getState(); + auto *LCtx = N->getLocationContext(); + if (!S) + return None; + + if (auto *DS = dyn_cast(S)) { + for (const auto *I : DS->decls()) + if (const VarDecl *VD = dyn_cast(I)) + if (const Expr *RHS = VD->getInit()) + if (RegionOfInterest->isSubRegionOf( + State->getLValue(VD, LCtx).getAsRegion())) + return RHS->getLocStart(); + } else if (auto *BO = dyn_cast(S)) { + const MemRegion *R = N->getSVal(BO->getLHS()).getAsRegion(); + const Expr* RHS = BO->getRHS(); + if (RegionOfInterest->isSubRegionOf(R)) { + return RHS->getLocStart(); + } + } + return None; + } + +}; + /// Emits an extra note at the return statement of an interesting stack frame. /// /// The returned value is marked as an interesting value, and if it's null, @@ -1073,13 +1168,6 @@ return "IDCVisitor"; } -/// \return name of the macro inside the location \p Loc. -static StringRef getMacroName(SourceLocation Loc, - BugReporterContext &BRC) { - return Lexer::getImmediateMacroName( - Loc, BRC.getSourceManager(), BRC.getASTContext().getLangOpts()); -} - std::shared_ptr SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ, const ExplodedNode *Pred, @@ -1139,21 +1227,16 @@ return nullptr; SourceLocation TerminatorLoc = CurTerminatorStmt->getLocStart(); - if (TerminatorLoc.isMacroID()) { - const SourceManager &SMgr = BRC.getSourceManager(); - std::pair TLInfo = SMgr.getDecomposedLoc(TerminatorLoc); - SrcMgr::SLocEntry SE = SMgr.getSLocEntry(TLInfo.first); - const SrcMgr::ExpansionInfo &EInfo = SE.getExpansion(); - if (EInfo.isFunctionMacroExpansion()) { - SourceLocation BugLoc = BugPoint->getStmt()->getLocStart(); - - // Suppress reports unless we are in that same macro. - if (!BugLoc.isMacroID() || - getMacroName(BugLoc, BRC) != getMacroName(TerminatorLoc, BRC)) { - BR.markInvalid("Suppress Macro IDC", CurLC); - } - return nullptr; + const SourceManager &SMgr = BRC.getSourceManager(); + if (isFunctionMacroExpansion(TerminatorLoc, SMgr)) { + SourceLocation BugLoc = BugPoint->getStmt()->getLocStart(); + + // Suppress reports unless we are in that same macro. + if (!BugLoc.isMacroID() || + getMacroName(BugLoc, BRC) != getMacroName(TerminatorLoc, BRC)) { + BR.markInvalid("Suppress Macro IDC", CurLC); } + return nullptr; } } return nullptr; @@ -1351,6 +1434,10 @@ report.addVisitor( llvm::make_unique(R->getAs())); + report.addVisitor( + llvm::make_unique( + R->getAs())); + report.markInteresting(R); report.markInteresting(V); report.addVisitor(llvm::make_unique(R)); Index: test/Analysis/diagnostics/macro-null-return-suppression.cpp =================================================================== --- /dev/null +++ test/Analysis/diagnostics/macro-null-return-suppression.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_analyze_cc1 -x c -analyzer-checker=core -analyzer-output=text -verify %s + +#define NULL 0 + +int test_noparammacro() { + int *x = NULL; // expected-note{{'x' initialized to a null pointer value}} + return *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} + // expected-note@-1{{Dereference of null pointer (loaded from variable 'x')}} +} + +#define DYN_CAST(X) (X ? (char*)X : 0) +char test_assignment(int *param) { + char *param2; + param2 = DYN_CAST(param); + return *param2; +} + +char test_declaration(int *param) { + char *param2 = DYN_CAST(param); + return *param2; +} + +// Warning should not be suppressed if it happens in the same macro. +#define DEREF_IN_MACRO(X) int fn() {int *p = 0; return *p; } + +DEREF_IN_MACRO(0) // expected-warning{{Dereference of null pointer}} + // expected-note@-1{{'p' initialized to a null}} + // expected-note@-2{{Dereference of null pointer}}