forked from OSchip/llvm-project
[analzyer] Migrate CallAndMessageChecker to CheckerV2.
llvm-svn: 126626
This commit is contained in:
parent
64fe456a6b
commit
6d6801c5c7
|
@ -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<CallAndMessageChecker> {
|
||||
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<CallExpr>, check::PreObjCMessage > {
|
||||
mutable llvm::OwningPtr<BugType> BT_call_null;
|
||||
mutable llvm::OwningPtr<BugType> BT_call_undef;
|
||||
mutable llvm::OwningPtr<BugType> BT_call_arg;
|
||||
mutable llvm::OwningPtr<BugType> BT_msg_undef;
|
||||
mutable llvm::OwningPtr<BugType> BT_msg_arg;
|
||||
mutable llvm::OwningPtr<BugType> 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<BugType> &BT);
|
||||
static bool PreVisitProcessArg(CheckerContext &C, SVal V,SourceRange argRange,
|
||||
const Expr *argEx, const char *BT_desc, llvm::OwningPtr<BugType> &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<BugType> &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<BugType> &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<BugType> &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<loc::ConcreteInt>(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<DefinedOrUnknownSVal>(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<CallAndMessageChecker>();
|
||||
}
|
||||
|
|
|
@ -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">;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
// <rdar://problem/6888289> - This test case shows that a nil instance
|
||||
// variable can possibly be initialized by a method.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue