diff options
author | Jordan Rose <jordan_rose@apple.com> | 2013-03-01 19:45:10 +0000 |
---|---|---|
committer | Jordan Rose <jordan_rose@apple.com> | 2013-03-01 19:45:10 +0000 |
commit | 9abf1b4577b75ffcc46afbdfb55de334f68f05c0 (patch) | |
tree | 2bcdb024e90e00d4b58d95513abf14121c8afd2c /lib/StaticAnalyzer/Core/BugReporterVisitors.cpp | |
parent | 516fb31d0536040334032e2af6b62cd6a5479d1c (diff) |
[analyzer] Suppress paths involving a reference whose rvalue is null.
Most map types have an operator[] that inserts a new element if the key
isn't found, then returns a reference to the value slot so that you can
assign into it. However, if the value type is a pointer, it will be
initialized to null. This is usually no problem.
However, if the user /knows/ the map contains a value for a particular key,
they may just use it immediately:
// From ClangSACheckersEmitter.cpp
recordGroupMap[group]->Checkers
In this case the analyzer reports a null dereference on the path where the
key is not in the map, even though the user knows that path is impossible
here. They could silence the warning by adding an assertion, but that means
splitting up the expression and introducing a local variable. (Note that
the analyzer has no way of knowing that recordGroupMap[group] will return
the same reference if called twice in a row!)
We already have logic that says a null dereference has a high chance of
being a false positive if the null came from an inlined function. This
patch simply extends that to references whose rvalues are null as well,
silencing several false positives in LLVM.
<rdar://problem/13239854>
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@176371 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Core/BugReporterVisitors.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/BugReporterVisitors.cpp | 46 |
1 files changed, 33 insertions, 13 deletions
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index d712c18b78..bb20c0d3c6 100644 --- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -222,13 +222,24 @@ public: // Don't print any more notes after this one. Mode = Satisfied; + const Expr *RetE = Ret->getRetValue(); + assert(RetE && "Tracking a return value for a void function"); + + // Handle cases where a reference is returned and then immediately used. + Optional<Loc> LValue; + if (RetE->isGLValue()) { + if ((LValue = V.getAs<Loc>())) { + SVal RValue = State->getRawSVal(*LValue, RetE->getType()); + if (RValue.getAs<DefinedSVal>()) + V = RValue; + } + } + // Ignore aggregate rvalues. if (V.getAs<nonloc::LazyCompoundVal>() || V.getAs<nonloc::CompoundVal>()) return 0; - const Expr *RetE = Ret->getRetValue(); - assert(RetE && "Tracking a return value for a void function"); RetE = RetE->IgnoreParenCasts(); // If we can't prove the return value is 0, just mark it interesting, and @@ -267,10 +278,20 @@ public: Out << "Returning zero"; } - // FIXME: We should have a more generalized location printing mechanism. - if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetE)) - if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(DR->getDecl())) - Out << " (loaded from '" << *DD << "')"; + if (LValue) { + if (const MemRegion *MR = LValue->getAsRegion()) { + if (MR->canPrintPretty()) { + Out << " (reference to '"; + MR->printPretty(Out); + Out << "')"; + } + } + } else { + // FIXME: We should have a more generalized location printing mechanism. + if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetE)) + if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(DR->getDecl())) + Out << " (loaded from '" << *DD << "')"; + } PathDiagnosticLocation L(Ret, BRC.getSourceManager(), StackFrame); return new PathDiagnosticEventPiece(L, Out.str()); @@ -766,6 +787,12 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, // track the constraints on its contents. SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext()); + // If the value came from an inlined function call, we should at least make + // sure that function isn't pruned in our output. + if (const Expr *E = dyn_cast<Expr>(S)) + S = E->IgnoreParenCasts(); + ReturnVisitor::addVisitorIfNecessary(N, S, report); + // Uncomment this to find cases where we aren't properly getting the // base value that was dereferenced. // assert(!V.isUnknownOrUndef()); @@ -777,18 +804,11 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, const MemRegion *RegionRVal = RVal.getAsRegion(); report.addVisitor(new UndefOrNullArgVisitor(L->getRegion())); - if (RegionRVal && isa<SymbolicRegion>(RegionRVal)) { report.markInteresting(RegionRVal); report.addVisitor(new TrackConstraintBRVisitor( loc::MemRegionVal(RegionRVal), false)); } - } else { - // Otherwise, if the value came from an inlined function call, - // we should at least make sure that function isn't pruned in our output. - if (const Expr *E = dyn_cast<Expr>(S)) - S = E->IgnoreParenCasts(); - ReturnVisitor::addVisitorIfNecessary(N, S, report); } return true; |