diff options
author | Jordan Rose <jordan_rose@apple.com> | 2012-08-15 21:56:23 +0000 |
---|---|---|
committer | Jordan Rose <jordan_rose@apple.com> | 2012-08-15 21:56:23 +0000 |
commit | 7f660857309a14c036a80ef90b40bf8f68fda9da (patch) | |
tree | ce02b420c45ce45f255370f25e56f4478e88d3fa /lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp | |
parent | b5f9eb8a0709082bba8e8de3a6c643928570aaa0 (diff) |
[analyzer] If we call a C++ method on an object, assume it's non-null.
This is analogous to our handling of pointer dereferences: if we
dereference a pointer that may or may not be null, we assume it's non-null
from then on.
While some implementations of C++ (including ours) allow you to call a
non-virtual method through a null pointer of object type, it is technically
disallowed by the C++ standard, and should not prune out any real paths in
practice.
[class.mfct.non-static]p1: A non-static member function may be called
for an object of its class type, or for an object of a class derived
from its class type...
(a null pointer value does not refer to an object)
We can also make the same assumption about function pointers.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@161992 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp | 12 |
1 files changed, 9 insertions, 3 deletions
diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp index 30f45c7685..5edcf09f11 100644 --- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp @@ -235,17 +235,20 @@ void CallAndMessageChecker::checkPreStmt(const CallExpr *CE, ProgramStateRef StNonNull, StNull; llvm::tie(StNonNull, StNull) = State->assume(cast<DefinedOrUnknownSVal>(L)); - // FIXME: Do we want to record the non-null assumption here? if (StNull && !StNonNull) { if (!BT_call_null) BT_call_null.reset( new BuiltinBug("Called function pointer is null (null dereference)")); emitBadCall(BT_call_null.get(), C, Callee); } + + C.addTransition(StNonNull); } void CallAndMessageChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { + ProgramStateRef State = C.getState(); + // If this is a call to a C++ method, check if the callee is null or // undefined. if (const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&Call)) { @@ -258,11 +261,9 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call, return; } - ProgramStateRef State = C.getState(); ProgramStateRef StNonNull, StNull; llvm::tie(StNonNull, StNull) = State->assume(cast<DefinedOrUnknownSVal>(V)); - // FIXME: Do we want to record the non-null assumption here? if (StNull && !StNonNull) { if (!BT_cxx_call_null) BT_cxx_call_null.reset(new BuiltinBug("Called C++ object pointer " @@ -270,6 +271,8 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call, emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr()); return; } + + State = StNonNull; } // Don't check for uninitialized field values in arguments if the @@ -291,6 +294,9 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call, Call.getArgExpr(i), /*IsFirstArgument=*/i == 0, checkUninitFields, Call, *BT)) return; + + // If we make it here, record our assumptions about the callee. + C.addTransition(State); } void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg, |