aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2013-02-24 07:21:01 +0000
committerTed Kremenek <kremenek@apple.com>2013-02-24 07:21:01 +0000
commit43b82b823a6113fdbee54243b280db9c55ef72cb (patch)
tree7fffa0612f4d6204f3554521ca6a77bd2f0ba87f /lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
parent0dd15d78fb0c99faa5df724139ba4c16a9a345c6 (diff)
[analyzer] tracking stores/constraints now works for ObjC ivars or struct fields.
This required more changes than I originally expected: - ObjCIvarRegion implements "canPrintPretty" et al - DereferenceChecker indicates the null pointer source is an ivar - bugreporter::trackNullOrUndefValue() uses an alternate algorithm to compute the location region to track by scouring the ExplodedGraph. This allows us to get the actual MemRegion for variables, ivars, fields, etc. We only hand construct a VarRegion for C++ references. - ExplodedGraph no longer drops nodes for expressions that are marked 'lvalue'. This is to facilitate the logic in the previous bullet. This may lead to a slight increase in size in the ExplodedGraph, which I have not measured, but it is likely not to be a big deal. I have validated each of the changed plist output. Fixes <rdar://problem/12114812> git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@175988 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Core/BugReporterVisitors.cpp')
-rw-r--r--lib/StaticAnalyzer/Core/BugReporterVisitors.cpp57
1 files changed, 48 insertions, 9 deletions
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index f59458ca6e..cb716a3154 100644
--- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -662,14 +662,47 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S,
// C++ user-defined implicit conversions, because those have a constructor
// or function call inside.
Ex = Ex->IgnoreParenCasts();
- if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) {
- // FIXME: Right now we only track VarDecls because it's non-trivial to
- // get a MemRegion for any other DeclRefExprs. <rdar://problem/12114812>
- if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
- ProgramStateManager &StateMgr = state->getStateManager();
- MemRegionManager &MRMgr = StateMgr.getRegionManager();
- const VarRegion *R = MRMgr.getVarRegion(VD, N->getLocationContext());
+ if (Ex->isLValue()) {
+ const MemRegion *R = 0;
+
+ // First check if this is a DeclRefExpr for a C++ reference type.
+ // For those, we want the location of the reference.
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+ if (VD->getType()->isReferenceType()) {
+ ProgramStateManager &StateMgr = state->getStateManager();
+ MemRegionManager &MRMgr = StateMgr.getRegionManager();
+ R = MRMgr.getVarRegion(VD, N->getLocationContext());
+ }
+ }
+ }
+
+ // For all other cases, find the location by scouring the ExplodedGraph.
+ if (!R) {
+ // Find the ExplodedNode where the lvalue (the value of 'Ex')
+ // was computed. We need this for getting the location value.
+ const ExplodedNode *LVNode = N;
+ const Expr *SearchEx = Ex;
+ if (const OpaqueValueExpr *OPE = dyn_cast<OpaqueValueExpr>(Ex)) {
+ SearchEx = OPE->getSourceExpr();
+ }
+ while (LVNode) {
+ if (Optional<PostStmt> P = LVNode->getLocation().getAs<PostStmt>()) {
+ if (P->getStmt() == SearchEx)
+ break;
+ }
+ LVNode = LVNode->getFirstPred();
+ }
+ assert(LVNode && "Unable to find the lvalue node.");
+ ProgramStateRef LVState = LVNode->getState();
+ if (Optional<Loc> L =
+ LVState->getSVal(Ex, LVNode->getLocationContext()).getAs<Loc>()) {
+ R = L->getAsRegion();
+ }
+ }
+
+ if (R) {
// Mark both the variable region and its contents as interesting.
SVal V = state->getRawSVal(loc::MemRegionVal(R));
@@ -692,6 +725,12 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S,
report.markInteresting(V);
report.addVisitor(new UndefOrNullArgVisitor(R));
+ if (isa<SymbolicRegion>(R)) {
+ TrackConstraintBRVisitor *VI =
+ new TrackConstraintBRVisitor(loc::MemRegionVal(R), false);
+ report.addVisitor(VI);
+ }
+
// If the contents are symbolic, find out when they became null.
if (V.getAsLocSymbol()) {
BugReporterVisitor *ConstraintTracker =
@@ -706,8 +745,8 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S,
}
}
- // If the expression does NOT refer to a variable, we can still track
- // constraints on its contents.
+ // If the expression is not an "lvalue expression", we can still
+ // track the constraints on its contents.
SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext());
// Uncomment this to find cases where we aren't properly getting the