summaryrefslogtreecommitdiffstats
path: root/lib/StaticAnalyzer
diff options
context:
space:
mode:
authorArtem Dergachev <artem.dergachev@gmail.com>2017-04-24 19:30:33 +0000
committerArtem Dergachev <artem.dergachev@gmail.com>2017-04-24 19:30:33 +0000
commit28cbd0c0d33991602e0d6e08f02e99ae58f4211b (patch)
tree967f24dd1bd88f81def4b63208d93423175d2fd1 /lib/StaticAnalyzer
parent43864bcdf23c093025ebc545d1a972a34db4838e (diff)
[analyzer] Improve suppression for inlined defensive checks before operator &.
Null dereferences are suppressed if the lvalue was constrained to 0 for the first time inside a sub-function that was inlined during analysis, because such constraint is a valid defensive check that does not, by itself, indicate that null pointer case is anyhow special for the caller. If further operations on the lvalue are performed, the symbolic lvalue is collapsed to concrete null pointer, and we need to track where does the null pointer come from. Improve such tracking for lvalue operations involving operator &. rdar://problem/27876009 Differential Revision: https://reviews.llvm.org/D31982 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@301224 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer')
-rw-r--r--lib/StaticAnalyzer/Core/BugReporterVisitors.cpp20
-rw-r--r--lib/StaticAnalyzer/Core/Store.cpp12
2 files changed, 29 insertions, 3 deletions
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 7309741d22..ec9fd6c75e 100644
--- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -961,6 +961,26 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N,
const Expr *Inner = nullptr;
if (const Expr *Ex = dyn_cast<Expr>(S)) {
Ex = Ex->IgnoreParenCasts();
+
+ // Performing operator `&' on an lvalue expression is essentially a no-op.
+ // Then, if we are taking addresses of fields or elements, these are also
+ // unlikely to matter.
+ // FIXME: There's a hack in our Store implementation that always computes
+ // field offsets around null pointers as if they are always equal to 0.
+ // The idea here is to report accesses to fields as null dereferences
+ // even though the pointer value that's being dereferenced is actually
+ // the offset of the field rather than exactly 0.
+ // See the FIXME in StoreManager's getLValueFieldOrIvar() method.
+ // This code interacts heavily with this hack; otherwise the value
+ // would not be null at all for most fields, so we'd be unable to track it.
+ if (const auto *Op = dyn_cast<UnaryOperator>(Ex))
+ if (Op->getOpcode() == UO_AddrOf && Op->getSubExpr()->isLValue()) {
+ Ex = Op->getSubExpr()->IgnoreParenCasts();
+ while (const auto *ME = dyn_cast<MemberExpr>(Ex)) {
+ Ex = ME->getBase()->IgnoreParenCasts();
+ }
+ }
+
if (ExplodedGraph::isInterestingLValueExpr(Ex) || CallEvent::isCallStmt(Ex))
Inner = Ex;
}
diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp
index ba48a60d5a..1af49f68cc 100644
--- a/lib/StaticAnalyzer/Core/Store.cpp
+++ b/lib/StaticAnalyzer/Core/Store.cpp
@@ -404,9 +404,15 @@ SVal StoreManager::getLValueFieldOrIvar(const Decl *D, SVal Base) {
case loc::ConcreteIntKind:
// While these seem funny, this can happen through casts.
- // FIXME: What we should return is the field offset. For example,
- // add the field offset to the integer value. That way funny things
+ // FIXME: What we should return is the field offset, not base. For example,
+ // add the field offset to the integer value. That way things
// like this work properly: &(((struct foo *) 0xa)->f)
+ // However, that's not easy to fix without reducing our abilities
+ // to catch null pointer dereference. Eg., ((struct foo *)0x0)->f = 7
+ // is a null dereference even though we're dereferencing offset of f
+ // rather than null. Coming up with an approach that computes offsets
+ // over null pointers properly while still being able to catch null
+ // dereferences might be worth it.
return Base;
default:
@@ -431,7 +437,7 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset,
// If the base is an unknown or undefined value, just return it back.
// FIXME: For absolute pointer addresses, we just return that value back as
// well, although in reality we should return the offset added to that
- // value.
+ // value. See also the similar FIXME in getLValueFieldOrIvar().
if (Base.isUnknownOrUndef() || Base.getAs<loc::ConcreteInt>())
return Base;