diff options
| author | George Karpenkov <ekarpenkov@apple.com> | 2018-02-03 00:55:21 +0000 |
|---|---|---|
| committer | George Karpenkov <ekarpenkov@apple.com> | 2018-02-03 00:55:21 +0000 |
| commit | 4316afbb44fe484bdcee6ffe272f65c31d9606bf (patch) | |
| tree | dbc46987aef4d34b373bf6d4e5d3c611a4f2c62c /clang/lib | |
| parent | 6eb9b9e593b133fe766a31442df4ad4a110e0fa2 (diff) | |
| download | bcm5719-llvm-4316afbb44fe484bdcee6ffe272f65c31d9606bf.tar.gz bcm5719-llvm-4316afbb44fe484bdcee6ffe272f65c31d9606bf.zip | |
[analyzer] Do not infer nullability inside function-like macros, even when macro is explicitly returning NULL
We already suppress such reports for inlined functions, we should then
get the same behavior for macros.
The underlying reason is that the same macro, can be called from many
different contexts, and nullability can only be expected in _some_ of
them.
Assuming that the macro can return null in _all_ of them sometimes leads
to a large number of false positives.
E.g. consider the test case for the dynamic cast implementation in
macro: in such cases, the bug report is unwanted.
Tracked in rdar://36304776
Differential Revision: https://reviews.llvm.org/D42404
llvm-svn: 324161
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp | 110 |
1 files changed, 103 insertions, 7 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 7484fcd1892..7a0e4d41be7 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -159,8 +159,108 @@ std::unique_ptr<PathDiagnosticPiece> BugReporterVisitor::getDefaultEndPath( 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; + while (SM.isMacroArgExpansion(Loc)) + Loc = SM.getImmediateExpansionRange(Loc).first; + std::pair<FileID, unsigned> TLInfo = SM.getDecomposedLoc(Loc); + SrcMgr::SLocEntry SE = SM.getSLocEntry(TLInfo.first); + const SrcMgr::ExpansionInfo &EInfo = SE.getExpansion(); + return EInfo.isFunctionMacroExpansion(); +} namespace { + +class MacroNullReturnSuppressionVisitor final + : public BugReporterVisitorImpl<MacroNullReturnSuppressionVisitor> { + + const SubRegion *RegionOfInterest; + +public: + MacroNullReturnSuppressionVisitor(const SubRegion *R) : RegionOfInterest(R) {} + + static void *getTag() { + static int Tag = 0; + return static_cast<void *>(&Tag); + } + + void Profile(llvm::FoldingSetNodeID &ID) const override { + ID.AddPointer(getTag()); + } + + std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) override { + auto BugPoint = BR.getErrorNode()->getLocation().getAs<StmtPoint>(); + if (!BugPoint) + return nullptr; + + 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; + } + + static void addMacroVisitorIfNecessary( + const ExplodedNode *N, const MemRegion *R, + bool EnableNullFPSuppression, BugReport &BR, + const SVal V) { + AnalyzerOptions &Options = N->getState()->getStateManager() + .getOwningEngine()->getAnalysisManager().options; + if (EnableNullFPSuppression && Options.shouldSuppressNullReturnPaths() + && V.getAs<Loc>()) + BR.addVisitor(llvm::make_unique<MacroNullReturnSuppressionVisitor>( + R->getAs<SubRegion>())); + } + +private: + /// \return Source location of right hand side of an assignment + /// into \c RegionOfInterest, empty optional if none found. + Optional<SourceLocation> 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<DeclStmt>(S)) { + if (const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl())) + if (const Expr *RHS = VD->getInit()) + if (RegionOfInterest->isSubRegionOf( + State->getLValue(VD, LCtx).getAsRegion())) + return RHS->getLocStart(); + } else if (auto *BO = dyn_cast<BinaryOperator>(S)) { + const MemRegion *R = N->getSVal(BO->getLHS()).getAsRegion(); + const Expr *RHS = BO->getRHS(); + if (BO->isAssignmentOp() && 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, @@ -854,13 +954,6 @@ const char *SuppressInlineDefensiveChecksVisitor::getTag() { 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<PathDiagnosticPiece> SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ, const ExplodedNode *Pred, @@ -1123,6 +1216,9 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, // Mark both the variable region and its contents as interesting. SVal V = LVState->getRawSVal(loc::MemRegionVal(R)); + MacroNullReturnSuppressionVisitor::addMacroVisitorIfNecessary( + N, R, EnableNullFPSuppression, report, V); + report.markInteresting(R); report.markInteresting(V); report.addVisitor(llvm::make_unique<UndefOrNullArgVisitor>(R)); |

