aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2013-03-01 19:45:10 +0000
committerJordan Rose <jordan_rose@apple.com>2013-03-01 19:45:10 +0000
commit9abf1b4577b75ffcc46afbdfb55de334f68f05c0 (patch)
tree2bcdb024e90e00d4b58d95513abf14121c8afd2c /lib/StaticAnalyzer
parent516fb31d0536040334032e2af6b62cd6a5479d1c (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')
-rw-r--r--lib/StaticAnalyzer/Core/BugReporterVisitors.cpp46
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;