]> granicus.if.org Git - clang/commitdiff
Add static analyzer check for calling a C++ instance method with a null/uninitialized...
authorTed Kremenek <kremenek@apple.com>
Thu, 26 Jul 2012 00:22:32 +0000 (00:22 +0000)
committerTed Kremenek <kremenek@apple.com>
Thu, 26 Jul 2012 00:22:32 +0000 (00:22 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@160767 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
test/Analysis/misc-ps-cxx0x.cpp

index 17ed692a6c189341585d7d32a9928a575373f78c..f3f169b4e0a9ba944a562ff869146a23c02d91e2 100644 (file)
@@ -31,6 +31,8 @@ class CallAndMessageChecker
                     check::PreCall > {
   mutable OwningPtr<BugType> BT_call_null;
   mutable OwningPtr<BugType> BT_call_undef;
+  mutable OwningPtr<BugType> BT_cxx_call_null;
+  mutable OwningPtr<BugType> BT_cxx_call_undef;
   mutable OwningPtr<BugType> BT_call_arg;
   mutable OwningPtr<BugType> BT_msg_undef;
   mutable OwningPtr<BugType> BT_objc_prop_undef;
@@ -239,14 +241,35 @@ void CallAndMessageChecker::checkPreStmt(const CallExpr *CE,
 
 void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
                                          CheckerContext &C) const {
+  // If this is a call to a C++ method, check if the callee is null or
+  // undefined.
+  // FIXME: Generalize this to CXXInstanceCall once it supports
+  // getCXXThisVal().
+  if (const CXXMemberCall *CC = dyn_cast<CXXMemberCall>(&Call)) {
+    SVal V = CC->getCXXThisVal();
+    if (V.isUndef()) {
+      if (!BT_cxx_call_undef)
+        BT_cxx_call_undef.reset(new BuiltinBug("Called C++ object pointer is "
+                                               "uninitialized"));
+      EmitBadCall(BT_cxx_call_undef.get(), C, CC->getOriginExpr());
+      return;
+    }
+    if (V.isZeroConstant()) {
+      if (!BT_cxx_call_null)
+        BT_cxx_call_null.reset(new BuiltinBug("Called C++ object pointer "
+                                              "is null"));
+      EmitBadCall(BT_cxx_call_null.get(), C, CC->getOriginExpr());
+      return;
+    }
+  }
+
   // Don't check for uninitialized field values in arguments if the
   // caller has a body that is available and we have the chance to inline it.
   // This is a hack, but is a reasonable compromise betweens sometimes warning
   // and sometimes not depending on if we decide to inline a function.
   const Decl *D = Call.getDecl();
   const bool checkUninitFields =
-    !(C.getAnalysisManager().shouldInlineCall() &&
-      (D && D->getBody()));
+    !(C.getAnalysisManager().shouldInlineCall() && (D && D->getBody()));
 
   OwningPtr<BugType> *BT;
   if (isa<ObjCMethodCall>(Call))
index 7712bb8dc3b7ea6b32686a97d6d8d57d51b91b9b..e1c78ed072361f0d7d162f92c17b7778c11b8bac 100644 (file)
@@ -87,4 +87,25 @@ void rdar11817693::operator=(const rdar11817693& src) {
   operator=(dynamic_cast<const rdar11817693_BaseBase&>(src));
 }
 
+// Test warning about null or uninitialized pointer values used as instance member
+// calls.
+class TestInstanceCall {
+public:
+  void foo() {}
+};
+
+void test_ic() {
+  TestInstanceCall *p;
+  p->foo(); // expected-warning {{Called C++ object pointer is uninitialized}}
+}
+
+void test_ic_null() {
+  TestInstanceCall *p = 0;
+  p->foo(); // expected-warning {{Called C++ object pointer is null}}
+}
+
+void test_ic_null(TestInstanceCall *p) {
+  if (!p)
+    p->foo(); // expected-warning {{Called C++ object pointer is null}}
+}