From d84f422ebfde2145bce79a8fa823e3393b392994 Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Mon, 28 Feb 2011 01:28:13 +0000 Subject: [PATCH] [analzyer] Migrate CallAndMessageChecker to CheckerV2. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126626 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Checkers/CallAndMessageChecker.cpp | 121 +++++++++--------- lib/StaticAnalyzer/Checkers/Checkers.td | 4 + lib/StaticAnalyzer/Checkers/ExprEngine.cpp | 1 - lib/StaticAnalyzer/Checkers/InternalChecks.h | 1 - ...undefined-larger-than-voidptr-ret-region.m | 2 +- ...ceiver-undefined-larger-than-voidptr-ret.m | 12 +- ...600344-nil-receiver-undefined-struct-ret.m | 4 +- test/Analysis/uninit-msg-expr.m | 4 +- test/Analysis/uninit-ps-rdar6145427.m | 4 +- 9 files changed, 78 insertions(+), 75 deletions(-) diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp index 415900eb00..e546c613b1 100644 --- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp @@ -12,62 +12,51 @@ // //===----------------------------------------------------------------------===// -#include "InternalChecks.h" +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/AST/ParentMap.h" #include "clang/Basic/TargetInfo.h" -#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h" using namespace clang; using namespace ento; namespace { class CallAndMessageChecker - : public CheckerVisitor { - BugType *BT_call_null; - BugType *BT_call_undef; - BugType *BT_call_arg; - BugType *BT_msg_undef; - BugType *BT_msg_arg; - BugType *BT_msg_ret; + : public CheckerV2< check::PreStmt, check::PreObjCMessage > { + mutable llvm::OwningPtr BT_call_null; + mutable llvm::OwningPtr BT_call_undef; + mutable llvm::OwningPtr BT_call_arg; + mutable llvm::OwningPtr BT_msg_undef; + mutable llvm::OwningPtr BT_msg_arg; + mutable llvm::OwningPtr BT_msg_ret; public: - CallAndMessageChecker() : - BT_call_null(0), BT_call_undef(0), BT_call_arg(0), - BT_msg_undef(0), BT_msg_arg(0), BT_msg_ret(0) {} - - static void *getTag() { - static int x = 0; - return &x; - } - void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); - void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg); - bool evalNilReceiver(CheckerContext &C, ObjCMessage msg); + void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; + void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const; private: - void PreVisitProcessArgs(CheckerContext &C, CallOrObjCMessage callOrMsg, - const char *BT_desc, BugType *&BT); - bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange argRange, - const Expr *argEx, const char *BT_desc, BugType *&BT); + static void PreVisitProcessArgs(CheckerContext &C,CallOrObjCMessage callOrMsg, + const char *BT_desc, llvm::OwningPtr &BT); + static bool PreVisitProcessArg(CheckerContext &C, SVal V,SourceRange argRange, + const Expr *argEx, const char *BT_desc, llvm::OwningPtr &BT); - void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE); + static void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE); void emitNilReceiverBug(CheckerContext &C, const ObjCMessage &msg, - ExplodedNode *N); + ExplodedNode *N) const; void HandleNilReceiver(CheckerContext &C, const GRState *state, - ObjCMessage msg); + ObjCMessage msg) const; - void LazyInit_BT(const char *desc, BugType *&BT) { + static void LazyInit_BT(const char *desc, llvm::OwningPtr &BT) { if (!BT) - BT = new BuiltinBug(desc); + BT.reset(new BuiltinBug(desc)); } }; } // end anonymous namespace -void ento::RegisterCallAndMessageChecker(ExprEngine &Eng) { - Eng.registerCheck(new CallAndMessageChecker()); -} - void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE) { ExplodedNode *N = C.generateSink(); @@ -83,7 +72,7 @@ void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C, void CallAndMessageChecker::PreVisitProcessArgs(CheckerContext &C, CallOrObjCMessage callOrMsg, const char *BT_desc, - BugType *&BT) { + llvm::OwningPtr &BT) { for (unsigned i = 0, e = callOrMsg.getNumArgs(); i != e; ++i) if (PreVisitProcessArg(C, callOrMsg.getArgSVal(i), callOrMsg.getArgSourceRange(i), callOrMsg.getArg(i), @@ -95,7 +84,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange argRange, const Expr *argEx, const char *BT_desc, - BugType *&BT) { + llvm::OwningPtr &BT) { if (V.isUndef()) { if (ExplodedNode *N = C.generateSink()) { @@ -198,25 +187,25 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, return false; } -void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C, - const CallExpr *CE){ +void CallAndMessageChecker::checkPreStmt(const CallExpr *CE, + CheckerContext &C) const{ const Expr *Callee = CE->getCallee()->IgnoreParens(); SVal L = C.getState()->getSVal(Callee); if (L.isUndef()) { if (!BT_call_undef) - BT_call_undef = - new BuiltinBug("Called function pointer is an uninitalized pointer value"); - EmitBadCall(BT_call_undef, C, CE); + BT_call_undef.reset(new BuiltinBug("Called function pointer is an " + "uninitalized pointer value")); + EmitBadCall(BT_call_undef.get(), C, CE); return; } if (isa(L)) { if (!BT_call_null) - BT_call_null = - new BuiltinBug("Called function pointer is null (null dereference)"); - EmitBadCall(BT_call_null, C, CE); + BT_call_null.reset( + new BuiltinBug("Called function pointer is null (null dereference)")); + EmitBadCall(BT_call_null.get(), C, CE); } PreVisitProcessArgs(C, CallOrObjCMessage(CE, C.getState()), @@ -224,18 +213,19 @@ void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C, BT_call_arg); } -void CallAndMessageChecker::preVisitObjCMessage(CheckerContext &C, - ObjCMessage msg) { +void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg, + CheckerContext &C) const { const GRState *state = C.getState(); // FIXME: Handle 'super'? - if (const Expr *receiver = msg.getInstanceReceiver()) - if (state->getSVal(receiver).isUndef()) { + if (const Expr *receiver = msg.getInstanceReceiver()) { + SVal recVal = state->getSVal(receiver); + if (recVal.isUndef()) { if (ExplodedNode *N = C.generateSink()) { if (!BT_msg_undef) - BT_msg_undef = - new BuiltinBug("Receiver in message expression is an uninitialized value"); + BT_msg_undef.reset(new BuiltinBug("Receiver in message expression is " + "an uninitialized value")); EnhancedBugReport *R = new EnhancedBugReport(*BT_msg_undef, BT_msg_undef->getName(), N); R->addRange(receiver->getSourceRange()); @@ -244,7 +234,20 @@ void CallAndMessageChecker::preVisitObjCMessage(CheckerContext &C, C.EmitReport(R); } return; + } else { + // Bifurcate the state into nil and non-nil ones. + DefinedOrUnknownSVal receiverVal = cast(recVal); + + const GRState *notNilState, *nilState; + llvm::tie(notNilState, nilState) = state->assume(receiverVal); + + // Handle receiver must be nil. + if (nilState && !notNilState) { + HandleNilReceiver(C, state, msg); + return; + } } + } const char *bugDesc = msg.isPropertySetter() ? "Argument for property setter is an uninitialized value" @@ -253,20 +256,14 @@ void CallAndMessageChecker::preVisitObjCMessage(CheckerContext &C, PreVisitProcessArgs(C, CallOrObjCMessage(msg, state), bugDesc, BT_msg_arg); } -bool CallAndMessageChecker::evalNilReceiver(CheckerContext &C, - ObjCMessage msg) { - HandleNilReceiver(C, C.getState(), msg); - return true; // Nil receiver is not handled elsewhere. -} - void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C, const ObjCMessage &msg, - ExplodedNode *N) { + ExplodedNode *N) const { if (!BT_msg_ret) - BT_msg_ret = + BT_msg_ret.reset( new BuiltinBug("Receiver in message expression is " - "'nil' and returns a garbage value"); + "'nil' and returns a garbage value")); llvm::SmallString<200> buf; llvm::raw_svector_ostream os(buf); @@ -292,7 +289,7 @@ static bool supportsNilWithFloatRet(const llvm::Triple &triple) { void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, const GRState *state, - ObjCMessage msg) { + ObjCMessage msg) const { ASTContext &Ctx = C.getASTContext(); // Check the return type of the message expression. A message to nil will @@ -356,3 +353,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, C.addTransition(state); } + +void ento::registerCallAndMessageChecker(CheckerManager &mgr) { + mgr.registerChecker(); +} diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td index 3edc3c247a..99556847b5 100644 --- a/lib/StaticAnalyzer/Checkers/Checkers.td +++ b/lib/StaticAnalyzer/Checkers/Checkers.td @@ -75,6 +75,10 @@ def ObjCUnusedIvarsChecker : Checker<"UnusedIvars">, let ParentPackage = Core in { +def CallAndMessageChecker : Checker<"CallAndMsg">, + HelpText<"Check for errors of call and objc message expressions">, + DescFile<"CallAndMessageChecker.cpp">; + def AdjustedReturnValueChecker : Checker<"AdjustRet">, HelpText<"Check to see if the return value of a function call is different than the caller expects">, DescFile<"AdjustedReturnValueChecker.cpp">; diff --git a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp index 443f62aa42..5b8bd18d81 100644 --- a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp @@ -321,7 +321,6 @@ static void RegisterInternalChecks(ExprEngine &Eng) { // object. // CallAndMessageChecker should be registered before AttrNonNullChecker, // where we assume arguments are not undefined. - RegisterCallAndMessageChecker(Eng); RegisterDereferenceChecker(Eng); } diff --git a/lib/StaticAnalyzer/Checkers/InternalChecks.h b/lib/StaticAnalyzer/Checkers/InternalChecks.h index 640a191f71..3dd04c3a17 100644 --- a/lib/StaticAnalyzer/Checkers/InternalChecks.h +++ b/lib/StaticAnalyzer/Checkers/InternalChecks.h @@ -22,7 +22,6 @@ namespace ento { class ExprEngine; // Foundational checks that handle basic semantics. -void RegisterCallAndMessageChecker(ExprEngine &Eng); void RegisterDereferenceChecker(ExprEngine &Eng); } // end GR namespace diff --git a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m index eeab4312fe..766999ed48 100644 --- a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m +++ b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret-region.m @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-constraints=range -analyzer-store=region -verify %s +// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core,core.experimental -analyzer-check-objc-mem -analyzer-constraints=range -analyzer-store=region -verify %s // - This test case shows that a nil instance // variable can possibly be initialized by a method. diff --git a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m index 4ba1015c9a..3024e545a4 100644 --- a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m +++ b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m @@ -1,9 +1,9 @@ -// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=basic %s 2>&1 | FileCheck -check-prefix=darwin8 %s -// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin8 %s -// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=basic %s 2>&1 | FileCheck -check-prefix=darwin9 %s -// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin9 %s -// RUN: %clang_cc1 -triple thumbv6-apple-darwin4.0.0-iphoneos -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=basic %s 2>&1 | FileCheck -check-prefix=darwin9 %s -// RUN: %clang_cc1 -triple thumbv6-apple-darwin4.0.0-iphoneos -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin9 %s +// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core,core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=basic %s 2>&1 | FileCheck -check-prefix=darwin8 %s +// RUN: %clang_cc1 -triple i386-apple-darwin8 -analyze -analyzer-checker=core,core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin8 %s +// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=basic %s 2>&1 | FileCheck -check-prefix=darwin9 %s +// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin9 %s +// RUN: %clang_cc1 -triple thumbv6-apple-darwin4.0.0-iphoneos -analyze -analyzer-checker=core,core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=basic %s 2>&1 | FileCheck -check-prefix=darwin9 %s +// RUN: %clang_cc1 -triple thumbv6-apple-darwin4.0.0-iphoneos -analyze -analyzer-checker=core,core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin9 %s @interface MyClass {} - (void *)voidPtrM; diff --git a/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m b/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m index 4932a526fc..8f4459468d 100644 --- a/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m +++ b/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=basic %s -verify -// RUN: %clang_cc1 -analyze -analyzer-checker=core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=region %s -verify +// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=basic %s -verify +// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -analyzer-check-objc-mem -analyzer-constraints=basic -analyzer-store=region %s -verify typedef struct Foo { int x; } Bar; diff --git a/test/Analysis/uninit-msg-expr.m b/test/Analysis/uninit-msg-expr.m index a8e2f1b655..a45badb4a3 100644 --- a/test/Analysis/uninit-msg-expr.m +++ b/test/Analysis/uninit-msg-expr.m @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=basic -verify %s -// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-check-objc-mem -analyzer-store=basic -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-check-objc-mem -analyzer-store=region -verify %s //===----------------------------------------------------------------------===// // The following code is reduced using delta-debugging from diff --git a/test/Analysis/uninit-ps-rdar6145427.m b/test/Analysis/uninit-ps-rdar6145427.m index ccaf2e8105..b6abdddcba 100644 --- a/test/Analysis/uninit-ps-rdar6145427.m +++ b/test/Analysis/uninit-ps-rdar6145427.m @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -analyze -verify -analyzer-store=basic -analyzer-check-objc-mem %s -// RUN: %clang_cc1 -analyze -verify -analyzer-store=region -analyzer-check-objc-mem %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -analyzer-store=basic -analyzer-check-objc-mem %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -analyzer-store=region -analyzer-check-objc-mem %s // Delta-Debugging reduced preamble. typedef signed char BOOL; -- 2.40.0