summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorGeorge Karpenkov <ekarpenkov@apple.com>2018-02-03 00:55:21 +0000
committerGeorge Karpenkov <ekarpenkov@apple.com>2018-02-03 00:55:21 +0000
commit4316afbb44fe484bdcee6ffe272f65c31d9606bf (patch)
treedbc46987aef4d34b373bf6d4e5d3c611a4f2c62c /clang/lib
parent6eb9b9e593b133fe766a31442df4ad4a110e0fa2 (diff)
downloadbcm5719-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.cpp110
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));
OpenPOWER on IntegriCloud