2008-02-15 06:13:12 +08:00
|
|
|
//=-- GRExprEngine.cpp - Path-Sensitive Expression-Level Dataflow ---*- C++ -*-=
|
2008-01-31 10:35:41 +08:00
|
|
|
//
|
2008-01-31 14:49:09 +08:00
|
|
|
// The LLVM Compiler Infrastructure
|
2008-01-16 07:55:06 +08:00
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2008-02-15 06:13:12 +08:00
|
|
|
// This file defines a meta-engine for path-sensitive dataflow analysis that
|
|
|
|
// is built on GREngine, but provides the boilerplate to execute transfer
|
|
|
|
// functions and build the ExplodedGraph at the expression level.
|
2008-01-16 07:55:06 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
2009-11-24 16:24:26 +08:00
|
|
|
#include "GRExprEngineInternalChecks.h"
|
2010-03-28 05:19:47 +08:00
|
|
|
#include "clang/Checker/BugReporter/BugType.h"
|
|
|
|
#include "clang/Checker/PathSensitive/AnalysisManager.h"
|
2010-01-25 12:41:41 +08:00
|
|
|
#include "clang/Checker/PathSensitive/GRExprEngine.h"
|
|
|
|
#include "clang/Checker/PathSensitive/GRExprEngineBuilders.h"
|
|
|
|
#include "clang/Checker/PathSensitive/Checker.h"
|
2010-01-12 01:06:35 +08:00
|
|
|
#include "clang/AST/CharUnits.h"
|
2009-04-26 09:32:48 +08:00
|
|
|
#include "clang/AST/ParentMap.h"
|
|
|
|
#include "clang/AST/StmtObjC.h"
|
2010-03-16 21:14:16 +08:00
|
|
|
#include "clang/AST/DeclCXX.h"
|
2009-06-14 09:54:56 +08:00
|
|
|
#include "clang/Basic/Builtins.h"
|
2009-04-26 09:32:48 +08:00
|
|
|
#include "clang/Basic/SourceManager.h"
|
2008-03-08 04:57:30 +08:00
|
|
|
#include "clang/Basic/SourceManager.h"
|
2009-03-11 10:41:36 +08:00
|
|
|
#include "clang/Basic/PrettyStackTrace.h"
|
2008-09-13 13:16:45 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2009-08-23 20:08:50 +08:00
|
|
|
#include "llvm/ADT/ImmutableList.h"
|
2008-07-11 06:03:41 +08:00
|
|
|
|
2008-02-27 14:07:00 +08:00
|
|
|
#ifndef NDEBUG
|
|
|
|
#include "llvm/Support/GraphWriter.h"
|
|
|
|
#endif
|
|
|
|
|
2008-02-15 06:16:04 +08:00
|
|
|
using namespace clang;
|
|
|
|
using llvm::dyn_cast;
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
using llvm::dyn_cast_or_null;
|
2008-02-15 06:16:04 +08:00
|
|
|
using llvm::cast;
|
|
|
|
using llvm::APSInt;
|
2008-01-24 03:59:44 +08:00
|
|
|
|
2010-02-26 23:43:34 +08:00
|
|
|
namespace {
|
|
|
|
// Trait class for recording returned expression in the state.
|
|
|
|
struct ReturnExpr {
|
|
|
|
static int TagInt;
|
|
|
|
typedef const Stmt *data_type;
|
|
|
|
};
|
|
|
|
int ReturnExpr::TagInt;
|
|
|
|
}
|
|
|
|
|
2009-11-26 05:51:20 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Utility functions.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
|
|
|
|
IdentifierInfo* II = &Ctx.Idents.get(name);
|
|
|
|
return Ctx.Selectors.getSelector(0, &II);
|
|
|
|
}
|
|
|
|
|
2009-12-23 06:13:46 +08:00
|
|
|
|
2010-02-16 07:02:46 +08:00
|
|
|
static QualType GetCalleeReturnType(const CallExpr *CE) {
|
2009-12-19 04:13:39 +08:00
|
|
|
const Expr *Callee = CE->getCallee();
|
|
|
|
QualType T = Callee->getType();
|
|
|
|
if (const PointerType *PT = T->getAs<PointerType>()) {
|
|
|
|
const FunctionType *FT = PT->getPointeeType()->getAs<FunctionType>();
|
|
|
|
T = FT->getResultType();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
const BlockPointerType *BT = T->getAs<BlockPointerType>();
|
|
|
|
T = BT->getPointeeType()->getAs<FunctionType>()->getResultType();
|
2010-01-10 06:58:54 +08:00
|
|
|
}
|
|
|
|
return T;
|
|
|
|
}
|
|
|
|
|
2010-02-16 07:02:46 +08:00
|
|
|
static bool CalleeReturnsReference(const CallExpr *CE) {
|
2010-01-10 06:58:54 +08:00
|
|
|
return (bool) GetCalleeReturnType(CE)->getAs<ReferenceType>();
|
2009-12-19 04:13:39 +08:00
|
|
|
}
|
|
|
|
|
2009-12-23 06:13:46 +08:00
|
|
|
static bool ReceiverReturnsReference(const ObjCMessageExpr *ME) {
|
|
|
|
const ObjCMethodDecl *MD = ME->getMethodDecl();
|
|
|
|
if (!MD)
|
|
|
|
return false;
|
2010-01-10 06:58:54 +08:00
|
|
|
return MD->getResultType()->getAs<ReferenceType>();
|
2009-12-23 06:13:46 +08:00
|
|
|
}
|
|
|
|
|
2010-01-10 06:58:54 +08:00
|
|
|
#ifndef NDEBUG
|
|
|
|
static bool ReceiverReturnsReferenceOrRecord(const ObjCMessageExpr *ME) {
|
|
|
|
const ObjCMethodDecl *MD = ME->getMethodDecl();
|
|
|
|
if (!MD)
|
|
|
|
return false;
|
|
|
|
QualType T = MD->getResultType();
|
|
|
|
return T->getAs<RecordType>() || T->getAs<ReferenceType>();
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool CalleeReturnsReferenceOrRecord(const CallExpr *CE) {
|
|
|
|
QualType T = GetCalleeReturnType(CE);
|
|
|
|
return T->getAs<ReferenceType>() || T->getAs<RecordType>();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2009-07-23 05:43:51 +08:00
|
|
|
// Batch auditor. DEPRECATED.
|
2008-04-16 07:06:53 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2008-07-12 02:37:32 +08:00
|
|
|
namespace {
|
|
|
|
|
2009-11-28 14:07:30 +08:00
|
|
|
class MappedBatchAuditor : public GRSimpleAPICheck {
|
2008-07-12 02:37:32 +08:00
|
|
|
typedef llvm::ImmutableList<GRSimpleAPICheck*> Checks;
|
|
|
|
typedef llvm::DenseMap<void*,Checks> MapTy;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-12 02:37:32 +08:00
|
|
|
MapTy M;
|
|
|
|
Checks::Factory F;
|
2009-03-31 01:53:05 +08:00
|
|
|
Checks AllStmts;
|
2008-07-12 02:37:32 +08:00
|
|
|
|
|
|
|
public:
|
2009-03-31 01:53:05 +08:00
|
|
|
MappedBatchAuditor(llvm::BumpPtrAllocator& Alloc) :
|
|
|
|
F(Alloc), AllStmts(F.GetEmptyList()) {}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-12 02:37:32 +08:00
|
|
|
virtual ~MappedBatchAuditor() {
|
|
|
|
llvm::DenseSet<GRSimpleAPICheck*> AlreadyVisited;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-12 02:37:32 +08:00
|
|
|
for (MapTy::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI)
|
|
|
|
for (Checks::iterator I=MI->second.begin(), E=MI->second.end(); I!=E;++I){
|
|
|
|
|
|
|
|
GRSimpleAPICheck* check = *I;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-12 02:37:32 +08:00
|
|
|
if (AlreadyVisited.count(check))
|
|
|
|
continue;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-12 02:37:32 +08:00
|
|
|
AlreadyVisited.insert(check);
|
|
|
|
delete check;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-31 01:53:05 +08:00
|
|
|
void AddCheck(GRSimpleAPICheck *A, Stmt::StmtClass C) {
|
2008-07-12 02:37:32 +08:00
|
|
|
assert (A && "Check cannot be null.");
|
|
|
|
void* key = reinterpret_cast<void*>((uintptr_t) C);
|
|
|
|
MapTy::iterator I = M.find(key);
|
|
|
|
M[key] = F.Concat(A, I == M.end() ? F.GetEmptyList() : I->second);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-31 01:53:05 +08:00
|
|
|
void AddCheck(GRSimpleAPICheck *A) {
|
|
|
|
assert (A && "Check cannot be null.");
|
2009-09-09 23:08:12 +08:00
|
|
|
AllStmts = F.Concat(A, AllStmts);
|
2009-03-31 01:53:05 +08:00
|
|
|
}
|
2009-02-05 07:49:09 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
virtual bool Audit(ExplodedNode* N, GRStateManager& VMgr) {
|
2009-03-31 01:53:05 +08:00
|
|
|
// First handle the auditors that accept all statements.
|
|
|
|
bool isSink = false;
|
|
|
|
for (Checks::iterator I = AllStmts.begin(), E = AllStmts.end(); I!=E; ++I)
|
|
|
|
isSink |= (*I)->Audit(N, VMgr);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-31 01:53:05 +08:00
|
|
|
// Next handle the auditors that accept only specific statements.
|
2009-07-23 06:35:28 +08:00
|
|
|
const Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
|
2008-07-12 02:37:32 +08:00
|
|
|
void* key = reinterpret_cast<void*>((uintptr_t) S->getStmtClass());
|
|
|
|
MapTy::iterator MI = M.find(key);
|
2009-09-09 23:08:12 +08:00
|
|
|
if (MI != M.end()) {
|
2009-03-31 01:53:05 +08:00
|
|
|
for (Checks::iterator I=MI->second.begin(), E=MI->second.end(); I!=E; ++I)
|
|
|
|
isSink |= (*I)->Audit(N, VMgr);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
return isSink;
|
2008-07-12 02:37:32 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
2009-07-23 05:43:51 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Checker worklist routines.
|
|
|
|
//===----------------------------------------------------------------------===//
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst,
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet &Src, bool isPrevisit) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-06-26 04:59:31 +08:00
|
|
|
// Determine if we already have a cached 'CheckersOrdered' vector
|
|
|
|
// specifically tailored for the provided <Stmt kind, isPrevisit>. This
|
|
|
|
// can reduce the number of checkers actually called.
|
|
|
|
CheckersOrdered *CO = &Checkers;
|
|
|
|
llvm::OwningPtr<CheckersOrdered> NewCO;
|
|
|
|
|
|
|
|
const std::pair<unsigned, unsigned> &K =
|
|
|
|
std::make_pair((unsigned)S->getStmtClass(), isPrevisit ? 1U : 0U);
|
|
|
|
|
|
|
|
CheckersOrdered *& CO_Ref = COCache[K];
|
|
|
|
|
|
|
|
if (!CO_Ref) {
|
|
|
|
// If we have no previously cached CheckersOrdered vector for this
|
|
|
|
// statement kind, then create one.
|
|
|
|
NewCO.reset(new CheckersOrdered);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Use the already cached set.
|
|
|
|
CO = CO_Ref;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CO->empty()) {
|
|
|
|
// If there are no checkers, return early without doing any
|
|
|
|
// more work.
|
2009-12-09 10:45:41 +08:00
|
|
|
Dst.insert(Src);
|
2009-12-02 13:49:12 +08:00
|
|
|
return;
|
2009-07-23 05:43:51 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
|
|
|
ExplodedNodeSet *PrevSet = &Src;
|
2010-06-26 04:59:31 +08:00
|
|
|
unsigned checkersEvaluated = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-06-30 15:28:52 +08:00
|
|
|
for (CheckersOrdered::iterator I=CO->begin(), E=CO->end(); I!=E; ++I){
|
2009-12-09 10:45:41 +08:00
|
|
|
ExplodedNodeSet *CurrSet = 0;
|
|
|
|
if (I+1 == E)
|
|
|
|
CurrSet = &Dst;
|
|
|
|
else {
|
|
|
|
CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
|
|
|
|
CurrSet->clear();
|
2010-02-16 07:02:46 +08:00
|
|
|
}
|
2009-10-29 10:09:30 +08:00
|
|
|
void *tag = I->first;
|
|
|
|
Checker *checker = I->second;
|
2010-06-26 04:59:31 +08:00
|
|
|
bool respondsToCallback = true;
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
|
2010-06-26 04:59:31 +08:00
|
|
|
NI != NE; ++NI) {
|
|
|
|
|
|
|
|
checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit,
|
|
|
|
respondsToCallback);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2009-07-23 05:43:51 +08:00
|
|
|
PrevSet = CurrSet;
|
2010-06-26 04:59:31 +08:00
|
|
|
|
|
|
|
if (NewCO.get()) {
|
|
|
|
++checkersEvaluated;
|
|
|
|
if (respondsToCallback)
|
|
|
|
NewCO->push_back(*I);
|
|
|
|
}
|
2009-07-23 05:43:51 +08:00
|
|
|
}
|
2010-06-26 04:59:31 +08:00
|
|
|
|
|
|
|
// If we built NewCO, check if we called all the checkers. This is important
|
|
|
|
// so that we know that we accurately determined the entire set of checkers
|
|
|
|
// that responds to this callback.
|
|
|
|
if (NewCO.get() && checkersEvaluated == Checkers.size())
|
|
|
|
CO_Ref = NewCO.take();
|
2009-07-23 05:43:51 +08:00
|
|
|
|
|
|
|
// Don't autotransition. The CheckerContext objects should do this
|
|
|
|
// automatically.
|
2009-12-02 13:49:12 +08:00
|
|
|
}
|
|
|
|
|
2010-02-16 07:02:46 +08:00
|
|
|
void GRExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME,
|
2009-12-02 13:49:12 +08:00
|
|
|
ExplodedNodeSet &Dst,
|
|
|
|
const GRState *state,
|
|
|
|
ExplodedNode *Pred) {
|
2009-12-09 20:16:07 +08:00
|
|
|
bool Evaluated = false;
|
|
|
|
ExplodedNodeSet DstTmp;
|
|
|
|
|
2009-12-02 13:49:12 +08:00
|
|
|
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) {
|
|
|
|
void *tag = I->first;
|
|
|
|
Checker *checker = I->second;
|
|
|
|
|
2009-12-09 20:16:07 +08:00
|
|
|
if (checker->GR_EvalNilReceiver(DstTmp, *Builder, *this, ME, Pred, state,
|
|
|
|
tag)) {
|
|
|
|
Evaluated = true;
|
2009-12-02 13:49:12 +08:00
|
|
|
break;
|
2009-12-09 20:16:07 +08:00
|
|
|
} else
|
|
|
|
// The checker didn't evaluate the expr. Restore the Dst.
|
|
|
|
DstTmp.clear();
|
2009-12-02 13:49:12 +08:00
|
|
|
}
|
2009-12-09 20:16:07 +08:00
|
|
|
|
|
|
|
if (Evaluated)
|
|
|
|
Dst.insert(DstTmp);
|
|
|
|
else
|
|
|
|
Dst.insert(Pred);
|
2009-07-23 05:43:51 +08:00
|
|
|
}
|
|
|
|
|
2009-12-07 17:17:35 +08:00
|
|
|
// CheckerEvalCall returns true if one of the checkers processed the node.
|
|
|
|
// This may return void when all call evaluation logic goes to some checker
|
|
|
|
// in the future.
|
2010-02-16 07:02:46 +08:00
|
|
|
bool GRExprEngine::CheckerEvalCall(const CallExpr *CE,
|
|
|
|
ExplodedNodeSet &Dst,
|
2009-12-07 17:17:35 +08:00
|
|
|
ExplodedNode *Pred) {
|
|
|
|
bool Evaluated = false;
|
2009-12-09 20:16:07 +08:00
|
|
|
ExplodedNodeSet DstTmp;
|
2009-12-07 17:17:35 +08:00
|
|
|
|
|
|
|
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) {
|
|
|
|
void *tag = I->first;
|
|
|
|
Checker *checker = I->second;
|
|
|
|
|
2009-12-09 20:16:07 +08:00
|
|
|
if (checker->GR_EvalCallExpr(DstTmp, *Builder, *this, CE, Pred, tag)) {
|
2009-12-07 17:17:35 +08:00
|
|
|
Evaluated = true;
|
|
|
|
break;
|
2009-12-09 20:16:07 +08:00
|
|
|
} else
|
|
|
|
// The checker didn't evaluate the expr. Restore the DstTmp set.
|
|
|
|
DstTmp.clear();
|
2009-12-07 17:17:35 +08:00
|
|
|
}
|
|
|
|
|
2009-12-09 20:16:07 +08:00
|
|
|
if (Evaluated)
|
|
|
|
Dst.insert(DstTmp);
|
|
|
|
else
|
|
|
|
Dst.insert(Pred);
|
|
|
|
|
2009-12-07 17:17:35 +08:00
|
|
|
return Evaluated;
|
|
|
|
}
|
|
|
|
|
2010-02-16 07:02:46 +08:00
|
|
|
// FIXME: This is largely copy-paste from CheckerVisit(). Need to
|
2009-11-04 12:24:16 +08:00
|
|
|
// unify.
|
2009-11-05 08:42:23 +08:00
|
|
|
void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE,
|
|
|
|
ExplodedNodeSet &Dst,
|
2009-11-04 12:24:16 +08:00
|
|
|
ExplodedNodeSet &Src,
|
|
|
|
SVal location, SVal val, bool isPrevisit) {
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-04 12:24:16 +08:00
|
|
|
if (Checkers.empty()) {
|
2009-12-09 10:45:41 +08:00
|
|
|
Dst.insert(Src);
|
2009-11-04 12:24:16 +08:00
|
|
|
return;
|
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-04 12:24:16 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
|
|
|
ExplodedNodeSet *PrevSet = &Src;
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-04 12:24:16 +08:00
|
|
|
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
|
|
|
|
{
|
2009-12-09 10:45:41 +08:00
|
|
|
ExplodedNodeSet *CurrSet = 0;
|
|
|
|
if (I+1 == E)
|
|
|
|
CurrSet = &Dst;
|
|
|
|
else {
|
|
|
|
CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
|
|
|
|
CurrSet->clear();
|
|
|
|
}
|
2009-12-19 04:13:39 +08:00
|
|
|
|
2009-11-04 12:24:16 +08:00
|
|
|
void *tag = I->first;
|
|
|
|
Checker *checker = I->second;
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-04 12:24:16 +08:00
|
|
|
for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
|
|
|
|
NI != NE; ++NI)
|
2009-11-05 08:42:23 +08:00
|
|
|
checker->GR_VisitBind(*CurrSet, *Builder, *this, AssignE, StoreE,
|
|
|
|
*NI, tag, location, val, isPrevisit);
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-04 12:24:16 +08:00
|
|
|
// Update which NodeSet is the current one.
|
|
|
|
PrevSet = CurrSet;
|
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-04 12:24:16 +08:00
|
|
|
// Don't autotransition. The CheckerContext objects should do this
|
|
|
|
// automatically.
|
|
|
|
}
|
2008-07-12 02:37:32 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Engine construction and deletion.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-11-26 05:51:20 +08:00
|
|
|
static void RegisterInternalChecks(GRExprEngine &Eng) {
|
|
|
|
// Register internal "built-in" BugTypes with the BugReporter. These BugTypes
|
|
|
|
// are different than what probably many checks will do since they don't
|
|
|
|
// create BugReports on-the-fly but instead wait until GRExprEngine finishes
|
|
|
|
// analyzing a function. Generation of BugReport objects is done via a call
|
|
|
|
// to 'FlushReports' from BugReporter.
|
|
|
|
// The following checks do not need to have their associated BugTypes
|
|
|
|
// explicitly registered with the BugReporter. If they issue any BugReports,
|
|
|
|
// their associated BugType will get registered with the BugReporter
|
|
|
|
// automatically. Note that the check itself is owned by the GRExprEngine
|
2010-02-16 07:02:46 +08:00
|
|
|
// object.
|
2010-02-04 08:47:48 +08:00
|
|
|
RegisterAdjustedReturnValueChecker(Eng);
|
2010-06-16 13:45:09 +08:00
|
|
|
// CallAndMessageChecker should be registered before AttrNonNullChecker,
|
|
|
|
// where we assume arguments are not undefined.
|
2009-11-26 05:51:20 +08:00
|
|
|
RegisterCallAndMessageChecker(Eng);
|
2010-06-16 13:45:09 +08:00
|
|
|
RegisterAttrNonNullChecker(Eng);
|
2009-11-26 05:51:20 +08:00
|
|
|
RegisterDereferenceChecker(Eng);
|
|
|
|
RegisterVLASizeChecker(Eng);
|
|
|
|
RegisterDivZeroChecker(Eng);
|
2010-07-17 04:41:41 +08:00
|
|
|
RegisterIdempotentOperationChecker(Eng);
|
2009-11-26 05:51:20 +08:00
|
|
|
RegisterReturnUndefChecker(Eng);
|
|
|
|
RegisterUndefinedArraySubscriptChecker(Eng);
|
|
|
|
RegisterUndefinedAssignmentChecker(Eng);
|
|
|
|
RegisterUndefBranchChecker(Eng);
|
2010-02-16 16:33:59 +08:00
|
|
|
RegisterUndefCapturedBlockVarChecker(Eng);
|
2009-11-26 05:51:20 +08:00
|
|
|
RegisterUndefResultChecker(Eng);
|
2010-06-09 14:08:24 +08:00
|
|
|
RegisterStackAddrLeakChecker(Eng);
|
2009-12-07 17:17:35 +08:00
|
|
|
|
|
|
|
// This is not a checker yet.
|
|
|
|
RegisterNoReturnFunctionChecker(Eng);
|
2009-12-08 17:07:59 +08:00
|
|
|
RegisterBuiltinFunctionChecker(Eng);
|
2009-12-09 20:23:28 +08:00
|
|
|
RegisterOSAtomicChecker(Eng);
|
2010-02-25 08:20:35 +08:00
|
|
|
RegisterUnixAPIChecker(Eng);
|
2010-02-25 13:44:09 +08:00
|
|
|
RegisterMacOSXAPIChecker(Eng);
|
2008-05-02 02:33:28 +08:00
|
|
|
}
|
|
|
|
|
2010-01-05 08:15:18 +08:00
|
|
|
GRExprEngine::GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf)
|
2009-08-15 11:17:38 +08:00
|
|
|
: AMgr(mgr),
|
2010-07-01 15:10:59 +08:00
|
|
|
CoreEngine(*this),
|
2008-04-10 05:41:14 +08:00
|
|
|
G(CoreEngine.getGraph()),
|
|
|
|
Builder(NULL),
|
2010-07-01 15:10:59 +08:00
|
|
|
StateMgr(getContext(), mgr.getStoreManagerCreator(),
|
2010-01-05 08:15:18 +08:00
|
|
|
mgr.getConstraintManagerCreator(), G.getAllocator(),
|
|
|
|
*this),
|
2008-04-10 05:41:14 +08:00
|
|
|
SymMgr(StateMgr.getSymbolManager()),
|
2009-04-10 00:46:55 +08:00
|
|
|
ValMgr(StateMgr.getValueManager()),
|
2009-07-16 09:32:00 +08:00
|
|
|
SVator(ValMgr.getSValuator()),
|
2008-05-02 02:33:28 +08:00
|
|
|
CurrentStmt(NULL),
|
2008-12-22 16:30:52 +08:00
|
|
|
NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
|
2010-07-01 15:10:59 +08:00
|
|
|
RaiseSel(GetNullarySelector("raise", getContext())),
|
2010-01-05 08:15:18 +08:00
|
|
|
BR(mgr, *this), TF(tf) {
|
2009-11-26 05:45:48 +08:00
|
|
|
// Register internal checks.
|
2009-11-26 05:51:20 +08:00
|
|
|
RegisterInternalChecks(*this);
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2010-01-05 08:15:18 +08:00
|
|
|
// FIXME: Eventually remove the TF object entirely.
|
|
|
|
TF->RegisterChecks(*this);
|
|
|
|
TF->RegisterPrinters(getStateManager().Printers);
|
2009-11-26 05:45:48 +08:00
|
|
|
}
|
2008-04-10 05:41:14 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
GRExprEngine::~GRExprEngine() {
|
2009-02-05 07:49:09 +08:00
|
|
|
BR.FlushReports();
|
2008-05-02 02:33:28 +08:00
|
|
|
delete [] NSExceptionInstanceRaiseSelectors;
|
2010-06-26 04:59:31 +08:00
|
|
|
|
|
|
|
// Delete the set of checkers.
|
2009-10-31 01:47:32 +08:00
|
|
|
for (CheckersOrdered::iterator I=Checkers.begin(), E=Checkers.end(); I!=E;++I)
|
2009-10-29 10:09:30 +08:00
|
|
|
delete I->second;
|
2010-06-26 04:59:31 +08:00
|
|
|
|
|
|
|
for (CheckersOrderedCache::iterator I=COCache.begin(), E=COCache.end();
|
|
|
|
I!=E;++I)
|
|
|
|
delete I->second;
|
2008-04-10 05:41:14 +08:00
|
|
|
}
|
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Utility methods.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2008-07-12 02:37:32 +08:00
|
|
|
void GRExprEngine::AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C) {
|
|
|
|
if (!BatchAuditor)
|
|
|
|
BatchAuditor.reset(new MappedBatchAuditor(getGraph().getAllocator()));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-12 02:37:32 +08:00
|
|
|
((MappedBatchAuditor*) BatchAuditor.get())->AddCheck(A, C);
|
2008-04-10 05:41:14 +08:00
|
|
|
}
|
|
|
|
|
2009-03-31 01:53:05 +08:00
|
|
|
void GRExprEngine::AddCheck(GRSimpleAPICheck *A) {
|
|
|
|
if (!BatchAuditor)
|
|
|
|
BatchAuditor.reset(new MappedBatchAuditor(getGraph().getAllocator()));
|
|
|
|
|
|
|
|
((MappedBatchAuditor*) BatchAuditor.get())->AddCheck(A);
|
|
|
|
}
|
|
|
|
|
2009-08-17 14:19:58 +08:00
|
|
|
const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) {
|
|
|
|
const GRState *state = StateMgr.getInitialState(InitLoc);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-10 04:36:12 +08:00
|
|
|
// Preconditions.
|
|
|
|
|
2009-04-10 08:59:50 +08:00
|
|
|
// FIXME: It would be nice if we had a more general mechanism to add
|
|
|
|
// such preconditions. Some day.
|
2009-12-18 03:17:27 +08:00
|
|
|
do {
|
2010-02-16 07:02:46 +08:00
|
|
|
const Decl *D = InitLoc->getDecl();
|
2009-12-18 03:17:27 +08:00
|
|
|
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
|
|
|
// Precondition: the first argument of 'main' is an integer guaranteed
|
|
|
|
// to be > 0.
|
|
|
|
const IdentifierInfo *II = FD->getIdentifier();
|
|
|
|
if (!II || !(II->getName() == "main" && FD->getNumParams() > 0))
|
|
|
|
break;
|
|
|
|
|
|
|
|
const ParmVarDecl *PD = FD->getParamDecl(0);
|
|
|
|
QualType T = PD->getType();
|
|
|
|
if (!T->isIntegerType())
|
|
|
|
break;
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-18 03:17:27 +08:00
|
|
|
const MemRegion *R = state->getRegion(PD, InitLoc);
|
|
|
|
if (!R)
|
|
|
|
break;
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal V = state->getSVal(loc::MemRegionVal(R));
|
2009-12-18 03:17:27 +08:00
|
|
|
SVal Constraint_untested = EvalBinOp(state, BinaryOperator::GT, V,
|
|
|
|
ValMgr.makeZeroVal(T),
|
|
|
|
getContext().IntTy);
|
|
|
|
|
|
|
|
DefinedOrUnknownSVal *Constraint =
|
|
|
|
dyn_cast<DefinedOrUnknownSVal>(&Constraint_untested);
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-18 03:17:27 +08:00
|
|
|
if (!Constraint)
|
|
|
|
break;
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-18 03:17:27 +08:00
|
|
|
if (const GRState *newState = state->Assume(*Constraint, true))
|
|
|
|
state = newState;
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-18 03:17:27 +08:00
|
|
|
break;
|
2009-04-10 08:59:50 +08:00
|
|
|
}
|
2009-12-18 03:17:27 +08:00
|
|
|
|
2010-02-16 07:02:46 +08:00
|
|
|
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
|
2009-12-18 03:17:27 +08:00
|
|
|
// Precondition: 'self' is always non-null upon entry to an Objective-C
|
|
|
|
// method.
|
|
|
|
const ImplicitParamDecl *SelfD = MD->getSelfDecl();
|
|
|
|
const MemRegion *R = state->getRegion(SelfD, InitLoc);
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal V = state->getSVal(loc::MemRegionVal(R));
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-18 03:17:27 +08:00
|
|
|
if (const Loc *LV = dyn_cast<Loc>(&V)) {
|
|
|
|
// Assume that the pointer value in 'self' is non-null.
|
|
|
|
state = state->Assume(*LV, true);
|
|
|
|
assert(state && "'self' cannot be null");
|
|
|
|
}
|
2009-09-10 04:36:12 +08:00
|
|
|
}
|
2009-12-18 03:17:27 +08:00
|
|
|
} while (0);
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-04-10 08:59:50 +08:00
|
|
|
return state;
|
2008-02-05 05:59:01 +08:00
|
|
|
}
|
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Top-level transfer function logic (Dispatcher).
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-01-05 08:15:18 +08:00
|
|
|
/// EvalAssume - Called by ConstraintManager. Used to call checker-specific
|
|
|
|
/// logic for handling assumptions on symbolic values.
|
|
|
|
const GRState *GRExprEngine::ProcessAssume(const GRState *state, SVal cond,
|
2010-02-16 07:02:46 +08:00
|
|
|
bool assumption) {
|
2010-01-05 08:15:18 +08:00
|
|
|
for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
|
|
|
|
if (!state)
|
2010-02-16 07:02:46 +08:00
|
|
|
return NULL;
|
|
|
|
|
2010-01-05 08:15:18 +08:00
|
|
|
state = I->second->EvalAssume(state, cond, assumption);
|
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2010-01-05 08:15:18 +08:00
|
|
|
if (!state)
|
|
|
|
return NULL;
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2010-01-05 08:15:18 +08:00
|
|
|
return TF->EvalAssume(state, cond, assumption);
|
|
|
|
}
|
|
|
|
|
2010-06-24 06:08:00 +08:00
|
|
|
void GRExprEngine::ProcessEndWorklist(bool hasWorkRemaining) {
|
|
|
|
for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
I->second->VisitEndAnalysis(G, BR, hasWorkRemaining);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::ProcessStmt(const CFGElement CE,GRStmtNodeBuilder& builder) {
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
CurrentStmt = CE.getStmt();
|
2009-03-11 10:41:36 +08:00
|
|
|
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
CurrentStmt->getLocStart(),
|
2009-03-11 10:41:36 +08:00
|
|
|
"Error evaluating statement");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
Builder = &builder;
|
2010-02-26 10:38:09 +08:00
|
|
|
EntryNode = builder.getBasePredecessor();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
// Set up our simple checks.
|
2008-07-12 02:37:32 +08:00
|
|
|
if (BatchAuditor)
|
|
|
|
Builder->setAuditor(BatchAuditor.get());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
// Create the cleaned state.
|
2009-12-15 06:15:06 +08:00
|
|
|
const ExplodedNode *BasePred = Builder->getBasePredecessor();
|
2010-03-05 12:45:36 +08:00
|
|
|
|
2010-07-02 04:09:55 +08:00
|
|
|
SymbolReaper SymReaper(BasePred->getLocationContext(), CurrentStmt, SymMgr);
|
2010-03-05 12:45:36 +08:00
|
|
|
|
2009-08-27 14:55:26 +08:00
|
|
|
CleanedState = AMgr.shouldPurgeDead()
|
2010-07-02 04:09:55 +08:00
|
|
|
? StateMgr.RemoveDeadBindings(EntryNode->getState(),
|
2010-03-17 11:35:08 +08:00
|
|
|
BasePred->getLocationContext()->getCurrentStackFrame(),
|
|
|
|
SymReaper)
|
2009-08-27 14:55:26 +08:00
|
|
|
: EntryNode->getState();
|
2009-01-22 06:26:05 +08:00
|
|
|
|
2008-04-25 02:31:42 +08:00
|
|
|
// Process any special transfer function for dead symbols.
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-01-22 06:26:05 +08:00
|
|
|
if (!SymReaper.hasDeadSymbols())
|
2008-04-25 07:35:58 +08:00
|
|
|
Tmp.Add(EntryNode);
|
2008-04-25 02:31:42 +08:00
|
|
|
else {
|
|
|
|
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
|
2008-04-25 07:35:58 +08:00
|
|
|
SaveOr OldHasGen(Builder->HasGeneratedNode);
|
|
|
|
|
2008-06-18 13:34:07 +08:00
|
|
|
SaveAndRestore<bool> OldPurgeDeadSymbols(Builder->PurgingDeadSymbols);
|
|
|
|
Builder->PurgingDeadSymbols = true;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-13 14:53:04 +08:00
|
|
|
// FIXME: This should soon be removed.
|
|
|
|
ExplodedNodeSet Tmp2;
|
2010-07-02 04:09:55 +08:00
|
|
|
getTF().EvalDeadSymbols(Tmp2, *this, *Builder, EntryNode,
|
2009-01-22 06:26:05 +08:00
|
|
|
CleanedState, SymReaper);
|
2008-04-25 07:35:58 +08:00
|
|
|
|
2009-11-13 14:53:04 +08:00
|
|
|
if (Checkers.empty())
|
2009-12-14 10:13:39 +08:00
|
|
|
Tmp.insert(Tmp2);
|
2009-11-13 14:53:04 +08:00
|
|
|
else {
|
|
|
|
ExplodedNodeSet Tmp3;
|
|
|
|
ExplodedNodeSet *SrcSet = &Tmp2;
|
|
|
|
for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
|
|
|
|
I != E; ++I) {
|
2009-12-09 10:45:41 +08:00
|
|
|
ExplodedNodeSet *DstSet = 0;
|
|
|
|
if (I+1 == E)
|
|
|
|
DstSet = &Tmp;
|
|
|
|
else {
|
|
|
|
DstSet = (SrcSet == &Tmp2) ? &Tmp3 : &Tmp2;
|
|
|
|
DstSet->clear();
|
|
|
|
}
|
|
|
|
|
2009-11-13 14:53:04 +08:00
|
|
|
void *tag = I->first;
|
|
|
|
Checker *checker = I->second;
|
|
|
|
for (ExplodedNodeSet::iterator NI = SrcSet->begin(), NE = SrcSet->end();
|
|
|
|
NI != NE; ++NI)
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
checker->GR_EvalDeadSymbols(*DstSet, *Builder, *this, CurrentStmt,
|
|
|
|
*NI, SymReaper, tag);
|
2009-11-13 14:53:04 +08:00
|
|
|
SrcSet = DstSet;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-25 07:35:58 +08:00
|
|
|
if (!Builder->BuildSinks && !Builder->HasGeneratedNode)
|
|
|
|
Tmp.Add(EntryNode);
|
2008-04-25 02:31:42 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-25 07:35:58 +08:00
|
|
|
bool HasAutoGenerated = false;
|
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
|
2008-04-25 07:35:58 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Dst;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
// Set the cleaned state.
|
2008-04-25 07:35:58 +08:00
|
|
|
Builder->SetCleanedState(*I == EntryNode ? CleanedState : GetState(*I));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
// Visit the statement.
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
if (CE.asLValue())
|
|
|
|
VisitLValue(cast<Expr>(CurrentStmt), *I, Dst);
|
|
|
|
else
|
|
|
|
Visit(CurrentStmt, *I, Dst);
|
2008-04-25 07:35:58 +08:00
|
|
|
|
|
|
|
// Do we need to auto-generate a node? We only need to do this to generate
|
|
|
|
// a node with a "cleaned" state; GRCoreEngine will actually handle
|
2009-09-09 23:08:12 +08:00
|
|
|
// auto-transitions for other cases.
|
2008-04-25 07:35:58 +08:00
|
|
|
if (Dst.size() == 1 && *Dst.begin() == EntryNode
|
|
|
|
&& !Builder->HasGeneratedNode && !HasAutoGenerated) {
|
|
|
|
HasAutoGenerated = true;
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
builder.generateNode(CurrentStmt, GetState(EntryNode), *I);
|
2008-04-25 07:35:58 +08:00
|
|
|
}
|
2008-04-25 02:31:42 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
// NULL out these variables to cleanup.
|
2008-04-25 07:35:58 +08:00
|
|
|
CleanedState = NULL;
|
|
|
|
EntryNode = NULL;
|
2008-07-18 05:27:31 +08:00
|
|
|
|
|
|
|
CurrentStmt = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
Builder = NULL;
|
|
|
|
}
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
|
|
|
|
ExplodedNodeSet& Dst) {
|
2009-03-11 10:41:36 +08:00
|
|
|
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
|
|
|
|
S->getLocStart(),
|
|
|
|
"Error evaluating statement");
|
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
// FIXME: add metadata to the CFG so that we can disable
|
|
|
|
// this check when we KNOW that there is no block-level subexpression.
|
|
|
|
// The motivation is that this check requires a hashtable lookup.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-25 11:33:41 +08:00
|
|
|
if (S != CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(S)) {
|
2008-04-16 07:06:53 +08:00
|
|
|
Dst.Add(Pred);
|
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
switch (S->getStmtClass()) {
|
2009-12-15 09:38:04 +08:00
|
|
|
// C++ stuff we don't support yet.
|
2010-04-16 01:33:31 +08:00
|
|
|
case Stmt::CXXBindReferenceExprClass:
|
|
|
|
case Stmt::CXXBindTemporaryExprClass:
|
|
|
|
case Stmt::CXXCatchStmtClass:
|
|
|
|
case Stmt::CXXConstructExprClass:
|
2009-12-15 09:38:04 +08:00
|
|
|
case Stmt::CXXDefaultArgExprClass:
|
2010-04-16 01:33:31 +08:00
|
|
|
case Stmt::CXXDependentScopeMemberExprClass:
|
2009-12-15 09:38:04 +08:00
|
|
|
case Stmt::CXXExprWithTemporariesClass:
|
2010-04-16 01:33:31 +08:00
|
|
|
case Stmt::CXXNullPtrLiteralExprClass:
|
|
|
|
case Stmt::CXXPseudoDestructorExprClass:
|
2009-12-15 09:38:04 +08:00
|
|
|
case Stmt::CXXTemporaryObjectExprClass:
|
2010-04-16 01:33:31 +08:00
|
|
|
case Stmt::CXXThrowExprClass:
|
|
|
|
case Stmt::CXXTryStmtClass:
|
|
|
|
case Stmt::CXXTypeidExprClass:
|
2009-12-15 09:38:04 +08:00
|
|
|
case Stmt::CXXUnresolvedConstructExprClass:
|
2010-07-08 14:14:04 +08:00
|
|
|
case Stmt::CXXScalarValueInitExprClass:
|
2010-04-16 01:33:31 +08:00
|
|
|
case Stmt::DependentScopeDeclRefExprClass:
|
|
|
|
case Stmt::UnaryTypeTraitExprClass:
|
|
|
|
case Stmt::UnresolvedLookupExprClass:
|
2009-12-15 09:38:04 +08:00
|
|
|
case Stmt::UnresolvedMemberExprClass:
|
2010-04-16 01:33:31 +08:00
|
|
|
{
|
2009-12-15 09:38:04 +08:00
|
|
|
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
|
|
|
|
Builder->BuildSinks = true;
|
|
|
|
MakeNode(Dst, S, Pred, GetState(Pred));
|
|
|
|
break;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-04-16 01:33:31 +08:00
|
|
|
// Cases that should never be evaluated simply because they shouldn't
|
|
|
|
// appear in the CFG.
|
|
|
|
case Stmt::BreakStmtClass:
|
|
|
|
case Stmt::CaseStmtClass:
|
|
|
|
case Stmt::CompoundStmtClass:
|
|
|
|
case Stmt::ContinueStmtClass:
|
|
|
|
case Stmt::DefaultStmtClass:
|
|
|
|
case Stmt::DoStmtClass:
|
|
|
|
case Stmt::GotoStmtClass:
|
|
|
|
case Stmt::IndirectGotoStmtClass:
|
|
|
|
case Stmt::LabelStmtClass:
|
|
|
|
case Stmt::NoStmtClass:
|
|
|
|
case Stmt::NullStmtClass:
|
|
|
|
case Stmt::SwitchCaseClass:
|
|
|
|
llvm_unreachable("Stmt should not be in analyzer evaluation loop");
|
|
|
|
break;
|
|
|
|
|
2010-06-23 03:05:10 +08:00
|
|
|
case Stmt::GNUNullExprClass: {
|
|
|
|
MakeNode(Dst, S, Pred, GetState(Pred)->BindExpr(S, ValMgr.makeNull()));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-04-16 01:33:31 +08:00
|
|
|
// Cases not handled yet; but will handle some day.
|
|
|
|
case Stmt::DesignatedInitExprClass:
|
|
|
|
case Stmt::ExtVectorElementExprClass:
|
|
|
|
case Stmt::ImaginaryLiteralClass:
|
|
|
|
case Stmt::ImplicitValueInitExprClass:
|
|
|
|
case Stmt::ObjCAtCatchStmtClass:
|
|
|
|
case Stmt::ObjCAtFinallyStmtClass:
|
|
|
|
case Stmt::ObjCAtSynchronizedStmtClass:
|
|
|
|
case Stmt::ObjCAtTryStmtClass:
|
|
|
|
case Stmt::ObjCEncodeExprClass:
|
|
|
|
case Stmt::ObjCImplicitSetterGetterRefExprClass:
|
|
|
|
case Stmt::ObjCIsaExprClass:
|
|
|
|
case Stmt::ObjCPropertyRefExprClass:
|
|
|
|
case Stmt::ObjCProtocolExprClass:
|
|
|
|
case Stmt::ObjCSelectorExprClass:
|
|
|
|
case Stmt::ObjCStringLiteralClass:
|
|
|
|
case Stmt::ObjCSuperExprClass:
|
|
|
|
case Stmt::ParenListExprClass:
|
|
|
|
case Stmt::PredefinedExprClass:
|
|
|
|
case Stmt::ShuffleVectorExprClass:
|
|
|
|
case Stmt::TypesCompatibleExprClass:
|
|
|
|
case Stmt::VAArgExprClass:
|
|
|
|
// Fall through.
|
|
|
|
|
|
|
|
// Cases we intentionally don't evaluate, since they don't need
|
|
|
|
// to be explicitly evaluated.
|
2010-04-13 21:15:19 +08:00
|
|
|
case Stmt::AddrLabelExprClass:
|
|
|
|
case Stmt::IntegerLiteralClass:
|
|
|
|
case Stmt::CharacterLiteralClass:
|
2010-04-14 14:29:29 +08:00
|
|
|
case Stmt::CXXBoolLiteralExprClass:
|
2010-04-13 21:15:19 +08:00
|
|
|
case Stmt::FloatingLiteralClass:
|
2008-04-16 07:06:53 +08:00
|
|
|
Dst.Add(Pred); // No-op. Simply propagate the current state unchanged.
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-22 12:56:29 +08:00
|
|
|
case Stmt::ArraySubscriptExprClass:
|
|
|
|
VisitArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Pred, Dst, false);
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
case Stmt::AsmStmtClass:
|
|
|
|
VisitAsmStmt(cast<AsmStmt>(S), Pred, Dst);
|
|
|
|
break;
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-08 06:05:27 +08:00
|
|
|
case Stmt::BlockDeclRefExprClass:
|
|
|
|
VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(S), Pred, Dst, false);
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-25 09:33:13 +08:00
|
|
|
case Stmt::BlockExprClass:
|
|
|
|
VisitBlockExpr(cast<BlockExpr>(S), Pred, Dst);
|
|
|
|
break;
|
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
case Stmt::BinaryOperatorClass: {
|
2010-07-20 14:22:24 +08:00
|
|
|
const BinaryOperator* B = cast<BinaryOperator>(S);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
if (B->isLogicalOp()) {
|
|
|
|
VisitLogicalExpr(B, Pred, Dst);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (B->getOpcode() == BinaryOperator::Comma) {
|
2009-02-13 09:45:31 +08:00
|
|
|
const GRState* state = GetState(Pred);
|
2010-02-09 00:18:51 +08:00
|
|
|
MakeNode(Dst, B, Pred, state->BindExpr(B, state->getSVal(B->getRHS())));
|
2008-04-16 07:06:53 +08:00
|
|
|
break;
|
|
|
|
}
|
2008-11-15 03:47:18 +08:00
|
|
|
|
2010-02-16 07:02:46 +08:00
|
|
|
if (AMgr.shouldEagerlyAssume() &&
|
2009-12-16 19:27:52 +08:00
|
|
|
(B->isRelationalOp() || B->isEqualityOp())) {
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
2009-10-30 15:19:39 +08:00
|
|
|
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp, false);
|
2009-09-09 23:08:12 +08:00
|
|
|
EvalEagerlyAssume(Dst, Tmp, cast<Expr>(S));
|
2009-02-26 06:32:02 +08:00
|
|
|
}
|
|
|
|
else
|
2009-10-30 15:19:39 +08:00
|
|
|
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst, false);
|
2009-02-26 06:32:02 +08:00
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
break;
|
|
|
|
}
|
2008-11-15 03:47:18 +08:00
|
|
|
|
2008-11-15 00:09:21 +08:00
|
|
|
case Stmt::CallExprClass:
|
|
|
|
case Stmt::CXXOperatorCallExprClass: {
|
2010-07-20 14:22:24 +08:00
|
|
|
const CallExpr* C = cast<CallExpr>(S);
|
2009-12-19 04:13:39 +08:00
|
|
|
VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, false);
|
2008-11-15 03:47:18 +08:00
|
|
|
break;
|
2008-04-16 07:06:53 +08:00
|
|
|
}
|
2008-11-15 03:47:18 +08:00
|
|
|
|
2010-04-01 15:58:50 +08:00
|
|
|
case Stmt::CXXMemberCallExprClass: {
|
2010-07-20 14:22:24 +08:00
|
|
|
const CXXMemberCallExpr *MCE = cast<CXXMemberCallExpr>(S);
|
2010-04-01 15:58:50 +08:00
|
|
|
VisitCXXMemberCallExpr(MCE, Pred, Dst);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-04-19 19:47:28 +08:00
|
|
|
case Stmt::CXXNewExprClass: {
|
2010-07-20 14:22:24 +08:00
|
|
|
const CXXNewExpr *NE = cast<CXXNewExpr>(S);
|
2010-04-19 19:47:28 +08:00
|
|
|
VisitCXXNewExpr(NE, Pred, Dst);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-04-21 10:17:31 +08:00
|
|
|
case Stmt::CXXDeleteExprClass: {
|
2010-07-20 14:22:24 +08:00
|
|
|
const CXXDeleteExpr *CDE = cast<CXXDeleteExpr>(S);
|
2010-04-21 10:17:31 +08:00
|
|
|
VisitCXXDeleteExpr(CDE, Pred, Dst);
|
|
|
|
break;
|
|
|
|
}
|
2008-04-16 07:06:53 +08:00
|
|
|
// FIXME: ChooseExpr is really a constant. We need to fix
|
|
|
|
// the CFG do not model them as explicit control-flow.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
case Stmt::ChooseExprClass: { // __builtin_choose_expr
|
2010-07-20 14:22:24 +08:00
|
|
|
const ChooseExpr* C = cast<ChooseExpr>(S);
|
2008-04-16 07:06:53 +08:00
|
|
|
VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst);
|
|
|
|
break;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
case Stmt::CompoundAssignOperatorClass:
|
2009-10-30 15:19:39 +08:00
|
|
|
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst, false);
|
2008-04-16 07:06:53 +08:00
|
|
|
break;
|
2008-11-07 18:38:33 +08:00
|
|
|
|
|
|
|
case Stmt::CompoundLiteralExprClass:
|
|
|
|
VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(S), Pred, Dst, false);
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
case Stmt::ConditionalOperatorClass: { // '?' operator
|
2010-07-20 14:22:24 +08:00
|
|
|
const ConditionalOperator* C = cast<ConditionalOperator>(S);
|
2008-04-16 07:06:53 +08:00
|
|
|
VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst);
|
|
|
|
break;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-12-16 19:27:52 +08:00
|
|
|
case Stmt::CXXThisExprClass:
|
|
|
|
VisitCXXThisExpr(cast<CXXThisExpr>(S), Pred, Dst);
|
|
|
|
break;
|
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
case Stmt::DeclRefExprClass:
|
2008-04-30 05:04:26 +08:00
|
|
|
VisitDeclRefExpr(cast<DeclRefExpr>(S), Pred, Dst, false);
|
2008-04-16 07:06:53 +08:00
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
case Stmt::DeclStmtClass:
|
|
|
|
VisitDeclStmt(cast<DeclStmt>(S), Pred, Dst);
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-12-24 09:49:25 +08:00
|
|
|
case Stmt::ForStmtClass:
|
|
|
|
// This case isn't for branch processing, but for handling the
|
|
|
|
// initialization of a condition variable.
|
|
|
|
VisitCondInit(cast<ForStmt>(S)->getConditionVariable(), S, Pred, Dst);
|
2010-02-16 07:02:46 +08:00
|
|
|
break;
|
2009-12-24 09:49:25 +08:00
|
|
|
|
2008-08-19 07:01:59 +08:00
|
|
|
case Stmt::ImplicitCastExprClass:
|
2010-04-13 20:38:32 +08:00
|
|
|
case Stmt::CStyleCastExprClass:
|
|
|
|
case Stmt::CXXStaticCastExprClass:
|
|
|
|
case Stmt::CXXDynamicCastExprClass:
|
|
|
|
case Stmt::CXXReinterpretCastExprClass:
|
|
|
|
case Stmt::CXXConstCastExprClass:
|
|
|
|
case Stmt::CXXFunctionalCastExprClass: {
|
2010-07-20 14:22:24 +08:00
|
|
|
const CastExpr* C = cast<CastExpr>(S);
|
2009-12-23 08:26:16 +08:00
|
|
|
VisitCast(C, C->getSubExpr(), Pred, Dst, false);
|
2008-04-16 07:06:53 +08:00
|
|
|
break;
|
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-23 12:49:01 +08:00
|
|
|
case Stmt::IfStmtClass:
|
|
|
|
// This case isn't for branch processing, but for handling the
|
|
|
|
// initialization of a condition variable.
|
2009-12-24 08:40:03 +08:00
|
|
|
VisitCondInit(cast<IfStmt>(S)->getConditionVariable(), S, Pred, Dst);
|
2009-12-23 12:49:01 +08:00
|
|
|
break;
|
2008-10-30 13:02:23 +08:00
|
|
|
|
|
|
|
case Stmt::InitListExprClass:
|
|
|
|
VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst);
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-17 08:03:18 +08:00
|
|
|
case Stmt::MemberExprClass:
|
2008-04-22 07:43:38 +08:00
|
|
|
VisitMemberExpr(cast<MemberExpr>(S), Pred, Dst, false);
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-17 08:03:18 +08:00
|
|
|
case Stmt::ObjCIvarRefExprClass:
|
|
|
|
VisitObjCIvarRefExpr(cast<ObjCIvarRefExpr>(S), Pred, Dst, false);
|
|
|
|
break;
|
2008-11-13 03:24:17 +08:00
|
|
|
|
|
|
|
case Stmt::ObjCForCollectionStmtClass:
|
|
|
|
VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S), Pred, Dst);
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-12-23 06:13:46 +08:00
|
|
|
case Stmt::ObjCMessageExprClass:
|
|
|
|
VisitObjCMessageExpr(cast<ObjCMessageExpr>(S), Pred, Dst, false);
|
2008-04-16 07:06:53 +08:00
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-12-10 04:18:58 +08:00
|
|
|
case Stmt::ObjCAtThrowStmtClass: {
|
|
|
|
// FIXME: This is not complete. We basically treat @throw as
|
|
|
|
// an abort.
|
|
|
|
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
|
|
|
|
Builder->BuildSinks = true;
|
|
|
|
MakeNode(Dst, S, Pred, GetState(Pred));
|
|
|
|
break;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
case Stmt::ParenExprClass:
|
2008-04-22 12:56:29 +08:00
|
|
|
Visit(cast<ParenExpr>(S)->getSubExpr()->IgnoreParens(), Pred, Dst);
|
2008-04-16 07:06:53 +08:00
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
case Stmt::ReturnStmtClass:
|
|
|
|
VisitReturnStmt(cast<ReturnStmt>(S), Pred, Dst);
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Completely reimplement __builtin_offsetof, based on a patch by Roberto
Amadini.
This change introduces a new expression node type, OffsetOfExpr, that
describes __builtin_offsetof. Previously, __builtin_offsetof was
implemented using a unary operator whose subexpression involved
various synthesized array-subscript and member-reference expressions,
which was ugly and made it very hard to instantiate as a
template. OffsetOfExpr represents the AST more faithfully, with proper
type source information and a more compact representation.
OffsetOfExpr also has support for dependent __builtin_offsetof
expressions; it can be value-dependent, but will never be
type-dependent (like sizeof or alignof). This commit introduces
template instantiation for __builtin_offsetof as well.
There are two major caveats to this patch:
1) CodeGen cannot handle the case where __builtin_offsetof is not a
constant expression, so it produces an error. So, to avoid
regressing in C, we retain the old UnaryOperator-based
__builtin_offsetof implementation in C while using the shiny new
OffsetOfExpr implementation in C++. The old implementation can go
away once we have proper CodeGen support for this case, which we
expect won't cause much trouble in C++.
2) __builtin_offsetof doesn't work well with non-POD class types,
particularly when the designated field is found within a base
class. I will address this in a subsequent patch.
Fixes PR5880 and a bunch of assertions when building Boost.Python
tests.
llvm-svn: 102542
2010-04-29 06:16:22 +08:00
|
|
|
case Stmt::OffsetOfExprClass:
|
|
|
|
VisitOffsetOfExpr(cast<OffsetOfExpr>(S), Pred, Dst);
|
|
|
|
break;
|
|
|
|
|
2008-11-12 01:56:53 +08:00
|
|
|
case Stmt::SizeOfAlignOfExprClass:
|
|
|
|
VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), Pred, Dst);
|
2008-04-16 07:06:53 +08:00
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
case Stmt::StmtExprClass: {
|
2010-07-20 14:22:24 +08:00
|
|
|
const StmtExpr* SE = cast<StmtExpr>(S);
|
2009-02-14 13:55:08 +08:00
|
|
|
|
|
|
|
if (SE->getSubStmt()->body_empty()) {
|
|
|
|
// Empty statement expression.
|
|
|
|
assert(SE->getType() == getContext().VoidTy
|
|
|
|
&& "Empty statement expression must have void type.");
|
|
|
|
Dst.Add(Pred);
|
|
|
|
break;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-14 13:55:08 +08:00
|
|
|
if (Expr* LastExpr = dyn_cast<Expr>(*SE->getSubStmt()->body_rbegin())) {
|
|
|
|
const GRState* state = GetState(Pred);
|
2010-02-09 00:18:51 +08:00
|
|
|
MakeNode(Dst, SE, Pred, state->BindExpr(SE, state->getSVal(LastExpr)));
|
2009-02-14 13:55:08 +08:00
|
|
|
}
|
2008-04-16 07:06:53 +08:00
|
|
|
else
|
|
|
|
Dst.Add(Pred);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
break;
|
|
|
|
}
|
2008-11-30 13:49:49 +08:00
|
|
|
|
|
|
|
case Stmt::StringLiteralClass:
|
|
|
|
VisitLValue(cast<StringLiteral>(S), Pred, Dst);
|
|
|
|
break;
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-24 08:40:03 +08:00
|
|
|
case Stmt::SwitchStmtClass:
|
|
|
|
// This case isn't for branch processing, but for handling the
|
|
|
|
// initialization of a condition variable.
|
|
|
|
VisitCondInit(cast<SwitchStmt>(S)->getConditionVariable(), S, Pred, Dst);
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-19 07:49:26 +08:00
|
|
|
case Stmt::UnaryOperatorClass: {
|
2010-07-20 14:22:24 +08:00
|
|
|
const UnaryOperator *U = cast<UnaryOperator>(S);
|
2009-12-16 19:27:52 +08:00
|
|
|
if (AMgr.shouldEagerlyAssume()&&(U->getOpcode() == UnaryOperator::LNot)) {
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
2009-03-19 07:49:26 +08:00
|
|
|
VisitUnaryOperator(U, Pred, Tmp, false);
|
|
|
|
EvalEagerlyAssume(Dst, Tmp, U);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
VisitUnaryOperator(U, Pred, Dst, false);
|
2008-04-30 05:04:26 +08:00
|
|
|
break;
|
2009-03-19 07:49:26 +08:00
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-24 08:54:56 +08:00
|
|
|
case Stmt::WhileStmtClass:
|
|
|
|
// This case isn't for branch processing, but for handling the
|
|
|
|
// initialization of a condition variable.
|
|
|
|
VisitCondInit(cast<WhileStmt>(S)->getConditionVariable(), S, Pred, Dst);
|
2010-02-16 07:02:46 +08:00
|
|
|
break;
|
2008-04-30 05:04:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitLValue(const Expr* Ex, ExplodedNode* Pred,
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet& Dst) {
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-23 12:09:43 +08:00
|
|
|
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
|
|
|
|
Ex->getLocStart(),
|
|
|
|
"Error evaluating statement");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-12-23 12:49:01 +08:00
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
Ex = Ex->IgnoreParens();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-12-16 19:27:52 +08:00
|
|
|
if (Ex != CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(Ex)){
|
2008-04-30 05:04:26 +08:00
|
|
|
Dst.Add(Pred);
|
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
switch (Ex->getStmtClass()) {
|
2009-12-23 08:26:16 +08:00
|
|
|
// C++ stuff we don't support yet.
|
2009-12-23 11:14:23 +08:00
|
|
|
case Stmt::CXXExprWithTemporariesClass:
|
2009-12-23 09:25:13 +08:00
|
|
|
case Stmt::CXXMemberCallExprClass:
|
2010-07-08 14:14:04 +08:00
|
|
|
case Stmt::CXXScalarValueInitExprClass: {
|
2009-12-23 08:26:16 +08:00
|
|
|
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
|
|
|
|
Builder->BuildSinks = true;
|
|
|
|
MakeNode(Dst, Ex, Pred, GetState(Pred));
|
|
|
|
break;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
case Stmt::ArraySubscriptExprClass:
|
|
|
|
VisitArraySubscriptExpr(cast<ArraySubscriptExpr>(Ex), Pred, Dst, true);
|
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-12-17 15:38:34 +08:00
|
|
|
case Stmt::BinaryOperatorClass:
|
|
|
|
case Stmt::CompoundAssignOperatorClass:
|
|
|
|
VisitBinaryOperator(cast<BinaryOperator>(Ex), Pred, Dst, true);
|
|
|
|
return;
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-08 06:05:27 +08:00
|
|
|
case Stmt::BlockDeclRefExprClass:
|
|
|
|
VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(Ex), Pred, Dst, true);
|
|
|
|
return;
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-19 04:13:39 +08:00
|
|
|
case Stmt::CallExprClass:
|
|
|
|
case Stmt::CXXOperatorCallExprClass: {
|
2010-07-20 14:22:24 +08:00
|
|
|
const CallExpr *C = cast<CallExpr>(Ex);
|
2010-01-10 06:58:54 +08:00
|
|
|
assert(CalleeReturnsReferenceOrRecord(C));
|
2010-02-16 07:02:46 +08:00
|
|
|
VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true);
|
2009-12-19 04:13:39 +08:00
|
|
|
break;
|
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-17 15:38:34 +08:00
|
|
|
case Stmt::CompoundLiteralExprClass:
|
|
|
|
VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(Ex), Pred, Dst, true);
|
2010-02-16 07:02:46 +08:00
|
|
|
return;
|
2009-12-08 06:05:27 +08:00
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
case Stmt::DeclRefExprClass:
|
|
|
|
VisitDeclRefExpr(cast<DeclRefExpr>(Ex), Pred, Dst, true);
|
|
|
|
return;
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-23 08:26:16 +08:00
|
|
|
case Stmt::ImplicitCastExprClass:
|
|
|
|
case Stmt::CStyleCastExprClass: {
|
2010-07-20 14:22:24 +08:00
|
|
|
const CastExpr *C = cast<CastExpr>(Ex);
|
2009-12-23 08:26:16 +08:00
|
|
|
QualType T = Ex->getType();
|
|
|
|
VisitCast(C, C->getSubExpr(), Pred, Dst, true);
|
|
|
|
break;
|
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
case Stmt::MemberExprClass:
|
|
|
|
VisitMemberExpr(cast<MemberExpr>(Ex), Pred, Dst, true);
|
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-12-17 15:38:34 +08:00
|
|
|
case Stmt::ObjCIvarRefExprClass:
|
|
|
|
VisitObjCIvarRefExpr(cast<ObjCIvarRefExpr>(Ex), Pred, Dst, true);
|
2008-10-28 05:54:31 +08:00
|
|
|
return;
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-23 06:13:46 +08:00
|
|
|
case Stmt::ObjCMessageExprClass: {
|
2010-07-20 14:22:24 +08:00
|
|
|
const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(Ex);
|
2010-01-10 06:58:54 +08:00
|
|
|
assert(ReceiverReturnsReferenceOrRecord(ME));
|
2010-02-16 07:02:46 +08:00
|
|
|
VisitObjCMessageExpr(ME, Pred, Dst, true);
|
2009-12-23 06:13:46 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-03-31 02:24:54 +08:00
|
|
|
case Stmt::ObjCIsaExprClass:
|
|
|
|
// FIXME: Do something more intelligent with 'x->isa = ...'.
|
|
|
|
// For now, just ignore the assignment.
|
|
|
|
return;
|
|
|
|
|
2008-10-18 01:24:14 +08:00
|
|
|
case Stmt::ObjCPropertyRefExprClass:
|
2009-08-21 01:02:02 +08:00
|
|
|
case Stmt::ObjCImplicitSetterGetterRefExprClass:
|
2008-10-18 01:24:14 +08:00
|
|
|
// FIXME: Property assignments are lvalues, but not really "locations".
|
|
|
|
// e.g.: self.x = something;
|
|
|
|
// Here the "self.x" really can translate to a method call (setter) when
|
|
|
|
// the assignment is made. Moreover, the entire assignment expression
|
|
|
|
// evaluate to whatever "something" is, not calling the "getter" for
|
|
|
|
// the property (which would make sense since it can have side effects).
|
|
|
|
// We'll probably treat this as a location, but not one that we can
|
|
|
|
// take the address of. Perhaps we need a new SVal class for cases
|
|
|
|
// like thsis?
|
|
|
|
// Note that we have a similar problem for bitfields, since they don't
|
|
|
|
// have "locations" in the sense that we can take their address.
|
|
|
|
Dst.Add(Pred);
|
2008-10-18 12:08:49 +08:00
|
|
|
return;
|
2008-10-25 22:18:57 +08:00
|
|
|
|
|
|
|
case Stmt::StringLiteralClass: {
|
2009-02-13 09:45:31 +08:00
|
|
|
const GRState* state = GetState(Pred);
|
2009-06-20 01:10:32 +08:00
|
|
|
SVal V = state->getLValue(cast<StringLiteral>(Ex));
|
2009-08-28 06:17:37 +08:00
|
|
|
MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V));
|
2008-10-25 22:18:57 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-12-17 15:38:34 +08:00
|
|
|
case Stmt::UnaryOperatorClass:
|
|
|
|
VisitUnaryOperator(cast<UnaryOperator>(Ex), Pred, Dst, true);
|
2009-10-30 15:19:39 +08:00
|
|
|
return;
|
2010-01-09 17:16:47 +08:00
|
|
|
|
|
|
|
// In C++, binding an rvalue to a reference requires to create an object.
|
2010-04-14 14:29:29 +08:00
|
|
|
case Stmt::CXXBoolLiteralExprClass:
|
2010-01-09 17:16:47 +08:00
|
|
|
case Stmt::IntegerLiteralClass:
|
|
|
|
CreateCXXTemporaryObject(Ex, Pred, Dst);
|
|
|
|
return;
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2010-06-26 07:51:38 +08:00
|
|
|
default: {
|
2008-10-18 12:15:35 +08:00
|
|
|
// Arbitrary subexpressions can return aggregate temporaries that
|
|
|
|
// can be used in a lvalue context. We need to enhance our support
|
|
|
|
// of such temporaries in both the environment and the store, so right
|
|
|
|
// now we just do a regular visit.
|
2010-06-26 07:51:38 +08:00
|
|
|
|
|
|
|
// NOTE: Do not use 'isAggregateType()' here as CXXRecordDecls that
|
|
|
|
// are non-pod are not aggregates.
|
|
|
|
assert ((isa<RecordType>(Ex->getType().getDesugaredType()) ||
|
|
|
|
isa<ArrayType>(Ex->getType().getDesugaredType())) &&
|
|
|
|
"Other kinds of expressions with non-aggregate/union/class types"
|
|
|
|
" do not have lvalues.");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-18 12:15:35 +08:00
|
|
|
Visit(Ex, Pred, Dst);
|
2010-06-26 07:51:38 +08:00
|
|
|
}
|
2008-04-16 07:06:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Block entrance. (Update counters).
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
bool GRExprEngine::ProcessBlockEntrance(const CFGBlock* B,
|
|
|
|
const ExplodedNode *Pred,
|
2008-04-16 07:06:53 +08:00
|
|
|
GRBlockCounter BC) {
|
2010-03-23 13:05:02 +08:00
|
|
|
return BC.getNumVisited(Pred->getLocationContext()->getCurrentStackFrame(),
|
2010-05-18 08:28:37 +08:00
|
|
|
B->getBlockID()) < AMgr.getMaxLoop();
|
2008-04-16 07:06:53 +08:00
|
|
|
}
|
|
|
|
|
2009-04-11 08:11:10 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Generic node creation.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-07-20 10:41:28 +08:00
|
|
|
ExplodedNode* GRExprEngine::MakeNode(ExplodedNodeSet& Dst, const Stmt* S,
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNode* Pred, const GRState* St,
|
|
|
|
ProgramPoint::Kind K, const void *tag) {
|
2009-04-11 08:11:10 +08:00
|
|
|
assert (Builder && "GRStmtNodeBuilder not present.");
|
|
|
|
SaveAndRestore<const void*> OldTag(Builder->Tag);
|
|
|
|
Builder->Tag = tag;
|
|
|
|
return Builder->MakeNode(Dst, S, Pred, St, K);
|
|
|
|
}
|
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Branch processing.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-02-13 09:45:31 +08:00
|
|
|
const GRState* GRExprEngine::MarkBranch(const GRState* state,
|
2010-07-20 14:22:24 +08:00
|
|
|
const Stmt* Terminator,
|
|
|
|
bool branchTaken) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-27 03:05:15 +08:00
|
|
|
switch (Terminator->getStmtClass()) {
|
|
|
|
default:
|
2009-02-13 09:45:31 +08:00
|
|
|
return state;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-27 03:05:15 +08:00
|
|
|
case Stmt::BinaryOperatorClass: { // '&&' and '||'
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
const BinaryOperator* B = cast<BinaryOperator>(Terminator);
|
2008-02-27 03:05:15 +08:00
|
|
|
BinaryOperator::Opcode Op = B->getOpcode();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-27 03:05:15 +08:00
|
|
|
assert (Op == BinaryOperator::LAnd || Op == BinaryOperator::LOr);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-27 03:05:15 +08:00
|
|
|
// For &&, if we take the true branch, then the value of the whole
|
|
|
|
// expression is that of the RHS expression.
|
|
|
|
//
|
|
|
|
// For ||, if we take the false branch, then the value of the whole
|
|
|
|
// expression is that of the RHS expression.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
const Expr* Ex = (Op == BinaryOperator::LAnd && branchTaken) ||
|
|
|
|
(Op == BinaryOperator::LOr && !branchTaken)
|
|
|
|
? B->getRHS() : B->getLHS();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-28 06:17:37 +08:00
|
|
|
return state->BindExpr(B, UndefinedVal(Ex));
|
2008-02-27 03:05:15 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-27 03:05:15 +08:00
|
|
|
case Stmt::ConditionalOperatorClass: { // ?:
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
const ConditionalOperator* C = cast<ConditionalOperator>(Terminator);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-27 03:05:15 +08:00
|
|
|
// For ?, if branchTaken == true then the value is either the LHS or
|
|
|
|
// the condition itself. (GNU extension).
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
const Expr* Ex;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-27 03:05:15 +08:00
|
|
|
if (branchTaken)
|
2009-09-09 23:08:12 +08:00
|
|
|
Ex = C->getLHS() ? C->getLHS() : C->getCond();
|
2008-02-27 03:05:15 +08:00
|
|
|
else
|
|
|
|
Ex = C->getRHS();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-28 06:17:37 +08:00
|
|
|
return state->BindExpr(C, UndefinedVal(Ex));
|
2008-02-27 03:05:15 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-27 03:05:15 +08:00
|
|
|
case Stmt::ChooseExprClass: { // ?:
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
const ChooseExpr* C = cast<ChooseExpr>(Terminator);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
const Expr* Ex = branchTaken ? C->getLHS() : C->getRHS();
|
2009-08-28 06:17:37 +08:00
|
|
|
return state->BindExpr(C, UndefinedVal(Ex));
|
2008-02-27 03:05:15 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-14 00:32:54 +08:00
|
|
|
/// RecoverCastedSymbol - A helper function for ProcessBranch that is used
|
|
|
|
/// to try to recover some path-sensitivity for casts of symbolic
|
|
|
|
/// integers that promote their values (which are currently not tracked well).
|
|
|
|
/// This function returns the SVal bound to Condition->IgnoreCasts if all the
|
|
|
|
// cast(s) did was sign-extend the original value.
|
|
|
|
static SVal RecoverCastedSymbol(GRStateManager& StateMgr, const GRState* state,
|
2010-07-20 14:22:24 +08:00
|
|
|
const Stmt* Condition, ASTContext& Ctx) {
|
2009-03-14 00:32:54 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
const Expr *Ex = dyn_cast<Expr>(Condition);
|
2009-03-14 00:32:54 +08:00
|
|
|
if (!Ex)
|
|
|
|
return UnknownVal();
|
|
|
|
|
|
|
|
uint64_t bits = 0;
|
|
|
|
bool bitsInit = false;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
while (const CastExpr *CE = dyn_cast<CastExpr>(Ex)) {
|
2009-03-14 00:32:54 +08:00
|
|
|
QualType T = CE->getType();
|
|
|
|
|
|
|
|
if (!T->isIntegerType())
|
|
|
|
return UnknownVal();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-14 00:32:54 +08:00
|
|
|
uint64_t newBits = Ctx.getTypeSize(T);
|
|
|
|
if (!bitsInit || newBits < bits) {
|
|
|
|
bitsInit = true;
|
|
|
|
bits = newBits;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-14 00:32:54 +08:00
|
|
|
Ex = CE->getSubExpr();
|
|
|
|
}
|
|
|
|
|
|
|
|
// We reached a non-cast. Is it a symbolic value?
|
|
|
|
QualType T = Ex->getType();
|
|
|
|
|
|
|
|
if (!bitsInit || !T->isIntegerType() || Ctx.getTypeSize(T) > bits)
|
|
|
|
return UnknownVal();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-02-09 00:18:51 +08:00
|
|
|
return state->getSVal(Ex);
|
2009-03-14 00:32:54 +08:00
|
|
|
}
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::ProcessBranch(const Stmt* Condition, const Stmt* Term,
|
2009-08-06 20:48:26 +08:00
|
|
|
GRBranchNodeBuilder& builder) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-16 06:29:00 +08:00
|
|
|
// Check for NULL conditions; e.g. "for(;;)"
|
2009-09-09 23:08:12 +08:00
|
|
|
if (!Condition) {
|
2008-02-16 06:29:00 +08:00
|
|
|
builder.markInfeasible(false);
|
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-11 11:54:24 +08:00
|
|
|
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
|
|
|
|
Condition->getLocStart(),
|
|
|
|
"Error evaluating branch");
|
2009-08-27 09:39:13 +08:00
|
|
|
|
2009-11-23 11:20:54 +08:00
|
|
|
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) {
|
|
|
|
void *tag = I->first;
|
|
|
|
Checker *checker = I->second;
|
|
|
|
checker->VisitBranchCondition(builder, *this, Condition, tag);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-23 11:20:54 +08:00
|
|
|
// If the branch condition is undefined, return;
|
|
|
|
if (!builder.isFeasible(true) && !builder.isFeasible(false))
|
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-23 11:20:54 +08:00
|
|
|
const GRState* PrevState = builder.getState();
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal X = PrevState->getSVal(Condition);
|
2008-01-31 07:03:39 +08:00
|
|
|
|
2009-11-23 11:20:54 +08:00
|
|
|
if (X.isUnknown()) {
|
|
|
|
// Give it a chance to recover from unknown.
|
|
|
|
if (const Expr *Ex = dyn_cast<Expr>(Condition)) {
|
|
|
|
if (Ex->getType()->isIntegerType()) {
|
|
|
|
// Try to recover some path-sensitivity. Right now casts of symbolic
|
|
|
|
// integers that promote their values are currently not tracked well.
|
|
|
|
// If 'Condition' is such an expression, try and recover the
|
|
|
|
// underlying value and use that instead.
|
|
|
|
SVal recovered = RecoverCastedSymbol(getStateManager(),
|
|
|
|
builder.getState(), Condition,
|
|
|
|
getContext());
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-23 11:20:54 +08:00
|
|
|
if (!recovered.isUnknown()) {
|
|
|
|
X = recovered;
|
|
|
|
}
|
2008-01-31 07:03:39 +08:00
|
|
|
}
|
2009-11-23 11:20:54 +08:00
|
|
|
}
|
|
|
|
// If the condition is still unknown, give up.
|
|
|
|
if (X.isUnknown()) {
|
|
|
|
builder.generateNode(MarkBranch(PrevState, Term, true), true);
|
|
|
|
builder.generateNode(MarkBranch(PrevState, Term, false), false);
|
2008-01-31 07:03:39 +08:00
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2008-01-31 07:03:39 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-23 11:20:54 +08:00
|
|
|
DefinedSVal V = cast<DefinedSVal>(X);
|
|
|
|
|
2008-03-01 04:27:50 +08:00
|
|
|
// Process the true branch.
|
2009-07-21 02:44:36 +08:00
|
|
|
if (builder.isFeasible(true)) {
|
2009-11-23 11:20:54 +08:00
|
|
|
if (const GRState *state = PrevState->Assume(V, true))
|
2009-07-21 02:44:36 +08:00
|
|
|
builder.generateNode(MarkBranch(state, Term, true), true);
|
|
|
|
else
|
|
|
|
builder.markInfeasible(true);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
// Process the false branch.
|
2009-07-21 02:44:36 +08:00
|
|
|
if (builder.isFeasible(false)) {
|
2009-11-23 11:20:54 +08:00
|
|
|
if (const GRState *state = PrevState->Assume(V, false))
|
2009-07-21 02:44:36 +08:00
|
|
|
builder.generateNode(MarkBranch(state, Term, false), false);
|
|
|
|
else
|
|
|
|
builder.markInfeasible(false);
|
|
|
|
}
|
2008-02-05 08:26:40 +08:00
|
|
|
}
|
|
|
|
|
2008-02-14 01:41:41 +08:00
|
|
|
/// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor
|
2008-02-13 08:24:44 +08:00
|
|
|
/// nodes by processing the 'effects' of a computed goto jump.
|
2009-08-06 20:48:26 +08:00
|
|
|
void GRExprEngine::ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) {
|
2008-02-13 08:24:44 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
const GRState *state = builder.getState();
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal V = state->getSVal(builder.getTarget());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-13 08:24:44 +08:00
|
|
|
// Three possibilities:
|
|
|
|
//
|
|
|
|
// (1) We know the computed label.
|
2008-02-28 17:25:22 +08:00
|
|
|
// (2) The label is NULL (or some other constant), or Undefined.
|
2008-02-13 08:24:44 +08:00
|
|
|
// (3) We have no clue about the label. Dispatch to all targets.
|
|
|
|
//
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
typedef GRIndirectGotoNodeBuilder::iterator iterator;
|
2008-02-13 08:24:44 +08:00
|
|
|
|
2008-10-17 13:57:07 +08:00
|
|
|
if (isa<loc::GotoLabel>(V)) {
|
2010-07-20 14:22:24 +08:00
|
|
|
const LabelStmt* L = cast<loc::GotoLabel>(V).getLabel();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-13 08:24:44 +08:00
|
|
|
for (iterator I=builder.begin(), E=builder.end(); I != E; ++I) {
|
2008-02-14 01:27:37 +08:00
|
|
|
if (I.getLabel() == L) {
|
2009-02-13 09:45:31 +08:00
|
|
|
builder.generateNode(I, state);
|
2008-02-13 08:24:44 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-13 08:24:44 +08:00
|
|
|
assert (false && "No block with label.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-10-17 13:57:07 +08:00
|
|
|
if (isa<loc::ConcreteInt>(V) || isa<UndefinedVal>(V)) {
|
2008-02-13 08:24:44 +08:00
|
|
|
// Dispatch to the first target and mark it as a sink.
|
2009-11-24 15:06:39 +08:00
|
|
|
//ExplodedNode* N = builder.generateNode(builder.begin(), state, true);
|
|
|
|
// FIXME: add checker visit.
|
|
|
|
// UndefBranches.insert(N);
|
2008-02-13 08:24:44 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-13 08:24:44 +08:00
|
|
|
// This is really a catch-all. We don't support symbolics yet.
|
2009-04-24 01:49:43 +08:00
|
|
|
// FIXME: Implement dispatch for symbolic pointers.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-13 08:24:44 +08:00
|
|
|
for (iterator I=builder.begin(), E=builder.end(); I != E; ++I)
|
2009-02-13 09:45:31 +08:00
|
|
|
builder.generateNode(I, state);
|
2008-02-13 08:24:44 +08:00
|
|
|
}
|
2008-02-05 08:26:40 +08:00
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitGuardedExpr(const Expr* Ex, const Expr* L,
|
|
|
|
const Expr* R,
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNode* Pred, ExplodedNodeSet& Dst) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-02-16 07:02:46 +08:00
|
|
|
assert(Ex == CurrentStmt &&
|
2009-12-16 19:27:52 +08:00
|
|
|
Pred->getLocationContext()->getCFG()->isBlkExpr(Ex));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-13 09:45:31 +08:00
|
|
|
const GRState* state = GetState(Pred);
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal X = state->getSVal(Ex);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
assert (X.isUndef());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
const Expr *SE = (Expr*) cast<UndefinedVal>(X).getData();
|
2009-09-09 23:08:12 +08:00
|
|
|
assert(SE);
|
2010-02-09 00:18:51 +08:00
|
|
|
X = state->getSVal(SE);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
// Make sure that we invalidate the previous binding.
|
2009-08-28 06:17:37 +08:00
|
|
|
MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, X, true));
|
2008-04-16 07:06:53 +08:00
|
|
|
}
|
|
|
|
|
2009-11-14 09:05:20 +08:00
|
|
|
/// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path
|
|
|
|
/// nodes when the control reaches the end of a function.
|
|
|
|
void GRExprEngine::ProcessEndPath(GREndPathNodeBuilder& builder) {
|
|
|
|
getTF().EvalEndPath(*this, builder);
|
|
|
|
StateMgr.EndPath(builder.getState());
|
2009-11-17 15:54:15 +08:00
|
|
|
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E;++I){
|
|
|
|
void *tag = I->first;
|
|
|
|
Checker *checker = I->second;
|
|
|
|
checker->EvalEndPath(builder, tag, *this);
|
|
|
|
}
|
2009-11-14 09:05:20 +08:00
|
|
|
}
|
|
|
|
|
2008-02-14 07:08:21 +08:00
|
|
|
/// ProcessSwitch - Called by GRCoreEngine. Used to generate successor
|
|
|
|
/// nodes by processing the 'effects' of a switch statement.
|
2009-09-09 23:08:12 +08:00
|
|
|
void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) {
|
|
|
|
typedef GRSwitchNodeBuilder::iterator iterator;
|
|
|
|
const GRState* state = builder.getState();
|
2010-07-20 14:22:24 +08:00
|
|
|
const Expr* CondE = builder.getCondition();
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal CondV_untested = state->getSVal(CondE);
|
2008-02-14 07:08:21 +08:00
|
|
|
|
2009-09-12 06:07:28 +08:00
|
|
|
if (CondV_untested.isUndef()) {
|
2009-11-24 15:06:39 +08:00
|
|
|
//ExplodedNode* N = builder.generateDefaultCaseNode(state, true);
|
2010-02-16 07:02:46 +08:00
|
|
|
// FIXME: add checker
|
2009-11-24 15:06:39 +08:00
|
|
|
//UndefBranches.insert(N);
|
|
|
|
|
2008-02-14 07:08:21 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-12 06:07:28 +08:00
|
|
|
DefinedOrUnknownSVal CondV = cast<DefinedOrUnknownSVal>(CondV_untested);
|
2008-02-19 06:57:02 +08:00
|
|
|
|
2009-09-12 06:07:28 +08:00
|
|
|
const GRState *DefaultSt = state;
|
2009-06-19 06:57:13 +08:00
|
|
|
bool defaultIsFeasible = false;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-22 02:02:17 +08:00
|
|
|
for (iterator I = builder.begin(), EI = builder.end(); I != EI; ++I) {
|
2010-07-20 14:22:24 +08:00
|
|
|
const CaseStmt* Case = cast<CaseStmt>(I.getCase());
|
2009-01-17 09:54:16 +08:00
|
|
|
|
|
|
|
// Evaluate the LHS of the case value.
|
|
|
|
Expr::EvalResult V1;
|
2009-09-09 23:08:12 +08:00
|
|
|
bool b = Case->getLHS()->Evaluate(V1, getContext());
|
|
|
|
|
2009-01-17 09:54:16 +08:00
|
|
|
// Sanity checks. These go away in Release builds.
|
2009-09-09 23:08:12 +08:00
|
|
|
assert(b && V1.Val.isInt() && !V1.HasSideEffects
|
2009-01-17 09:54:16 +08:00
|
|
|
&& "Case condition must evaluate to an integer constant.");
|
2009-09-09 23:08:12 +08:00
|
|
|
b = b; // silence unused variable warning
|
|
|
|
assert(V1.Val.getInt().getBitWidth() ==
|
2009-01-17 09:54:16 +08:00
|
|
|
getContext().getTypeSize(CondE->getType()));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-14 07:08:21 +08:00
|
|
|
// Get the RHS of the case, if it exists.
|
2009-01-17 09:54:16 +08:00
|
|
|
Expr::EvalResult V2;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
if (const Expr* E = Case->getRHS()) {
|
2009-01-17 09:54:16 +08:00
|
|
|
b = E->Evaluate(V2, getContext());
|
2009-09-09 23:08:12 +08:00
|
|
|
assert(b && V2.Val.isInt() && !V2.HasSideEffects
|
2009-01-17 09:54:16 +08:00
|
|
|
&& "Case condition must evaluate to an integer constant.");
|
|
|
|
b = b; // silence unused variable warning
|
2008-02-14 07:08:21 +08:00
|
|
|
}
|
2008-03-18 06:17:56 +08:00
|
|
|
else
|
|
|
|
V2 = V1;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-14 07:08:21 +08:00
|
|
|
// FIXME: Eventually we should replace the logic below with a range
|
|
|
|
// comparison, rather than concretize the values within the range.
|
2008-02-22 02:02:17 +08:00
|
|
|
// This should be easy once we have "ranges" for NonLVals.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-18 06:17:56 +08:00
|
|
|
do {
|
2009-09-09 23:08:12 +08:00
|
|
|
nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1.Val.getInt()));
|
2010-01-09 02:54:04 +08:00
|
|
|
DefinedOrUnknownSVal Res = SVator.EvalEQ(DefaultSt ? DefaultSt : state,
|
|
|
|
CondV, CaseVal);
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
// Now "assume" that the case matches.
|
2009-09-12 06:07:28 +08:00
|
|
|
if (const GRState* stateNew = state->Assume(Res, true)) {
|
2009-06-19 06:57:13 +08:00
|
|
|
builder.generateCaseStmtNode(I, stateNew);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-14 07:08:21 +08:00
|
|
|
// If CondV evaluates to a constant, then we know that this
|
|
|
|
// is the *only* case that we can take, so stop evaluating the
|
|
|
|
// others.
|
2008-10-17 13:57:07 +08:00
|
|
|
if (isa<nonloc::ConcreteInt>(CondV))
|
2008-02-14 07:08:21 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-14 07:08:21 +08:00
|
|
|
// Now "assume" that the case doesn't match. Add this state
|
|
|
|
// to the default state (if it is feasible).
|
2010-01-09 02:54:04 +08:00
|
|
|
if (DefaultSt) {
|
|
|
|
if (const GRState *stateNew = DefaultSt->Assume(Res, false)) {
|
|
|
|
defaultIsFeasible = true;
|
|
|
|
DefaultSt = stateNew;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
defaultIsFeasible = false;
|
|
|
|
DefaultSt = NULL;
|
|
|
|
}
|
2008-04-23 13:03:18 +08:00
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2008-03-18 06:17:56 +08:00
|
|
|
// Concretize the next value in the range.
|
2009-01-17 09:54:16 +08:00
|
|
|
if (V1.Val.getInt() == V2.Val.getInt())
|
2008-03-18 06:17:56 +08:00
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-01-17 09:54:16 +08:00
|
|
|
++V1.Val.getInt();
|
|
|
|
assert (V1.Val.getInt() <= V2.Val.getInt());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-18 06:17:56 +08:00
|
|
|
} while (true);
|
2008-02-14 07:08:21 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-14 07:08:21 +08:00
|
|
|
// If we reach here, than we know that the default branch is
|
2009-09-09 23:08:12 +08:00
|
|
|
// possible.
|
2009-06-19 06:57:13 +08:00
|
|
|
if (defaultIsFeasible) builder.generateDefaultCaseNode(DefaultSt);
|
2008-02-14 07:08:21 +08:00
|
|
|
}
|
|
|
|
|
2010-02-26 03:01:53 +08:00
|
|
|
void GRExprEngine::ProcessCallEnter(GRCallEnterNodeBuilder &B) {
|
2010-07-19 09:31:21 +08:00
|
|
|
const StackFrameContext *LocCtx
|
|
|
|
= AMgr.getStackFrame(const_cast<AnalysisContext *>(B.getCalleeContext()),
|
|
|
|
B.getLocationContext(),
|
|
|
|
B.getCallExpr(),
|
|
|
|
B.getBlock(),
|
|
|
|
B.getIndex());
|
2010-02-26 03:01:53 +08:00
|
|
|
|
|
|
|
const GRState *state = B.getState();
|
|
|
|
state = getStoreManager().EnterStackFrame(state, LocCtx);
|
|
|
|
|
|
|
|
B.GenerateNode(state, LocCtx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GRExprEngine::ProcessCallExit(GRCallExitNodeBuilder &B) {
|
|
|
|
const GRState *state = B.getState();
|
|
|
|
const ExplodedNode *Pred = B.getPredecessor();
|
|
|
|
const StackFrameContext *LocCtx =
|
|
|
|
cast<StackFrameContext>(Pred->getLocationContext());
|
|
|
|
const Stmt *CE = LocCtx->getCallSite();
|
|
|
|
|
2010-02-26 23:43:34 +08:00
|
|
|
// If the callee returns an expression, bind its value to CallExpr.
|
|
|
|
const Stmt *ReturnedExpr = state->get<ReturnExpr>();
|
|
|
|
if (ReturnedExpr) {
|
|
|
|
SVal RetVal = state->getSVal(ReturnedExpr);
|
|
|
|
state = state->BindExpr(CE, RetVal);
|
2010-03-23 16:09:29 +08:00
|
|
|
// Clear the return expr GDM.
|
2010-03-25 09:39:39 +08:00
|
|
|
state = state->remove<ReturnExpr>();
|
2010-02-26 23:43:34 +08:00
|
|
|
}
|
|
|
|
|
2010-03-23 17:13:17 +08:00
|
|
|
// Bind the constructed object value to CXXConstructExpr.
|
|
|
|
if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) {
|
2010-04-01 15:58:50 +08:00
|
|
|
const CXXThisRegion *ThisR = getCXXThisRegion(CCE->getConstructor(),LocCtx);
|
2010-03-23 17:13:17 +08:00
|
|
|
// We might not have 'this' region in the binding if we didn't inline
|
|
|
|
// the ctor call.
|
|
|
|
SVal ThisV = state->getSVal(ThisR);
|
|
|
|
loc::MemRegionVal *V = dyn_cast<loc::MemRegionVal>(&ThisV);
|
|
|
|
if (V) {
|
|
|
|
SVal ObjVal = state->getSVal(V->getRegion());
|
|
|
|
assert(isa<nonloc::LazyCompoundVal>(ObjVal));
|
|
|
|
state = state->BindExpr(CCE, ObjVal);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-26 03:01:53 +08:00
|
|
|
B.GenerateNode(state);
|
|
|
|
}
|
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Transfer functions: logical operations ('&&', '||').
|
|
|
|
//===----------------------------------------------------------------------===//
|
2008-02-14 07:08:21 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode* Pred,
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet& Dst) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 01:10:32 +08:00
|
|
|
assert(B->getOpcode() == BinaryOperator::LAnd ||
|
|
|
|
B->getOpcode() == BinaryOperator::LOr);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-12-16 19:27:52 +08:00
|
|
|
assert(B==CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(B));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-13 09:45:31 +08:00
|
|
|
const GRState* state = GetState(Pred);
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal X = state->getSVal(B);
|
2009-06-20 01:10:32 +08:00
|
|
|
assert(X.isUndef());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-12 06:07:28 +08:00
|
|
|
const Expr *Ex = (const Expr*) cast<UndefinedVal>(X).getData();
|
2009-06-20 01:10:32 +08:00
|
|
|
assert(Ex);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-27 03:05:15 +08:00
|
|
|
if (Ex == B->getRHS()) {
|
2010-02-09 00:18:51 +08:00
|
|
|
X = state->getSVal(Ex);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-28 17:25:22 +08:00
|
|
|
// Handle undefined values.
|
|
|
|
if (X.isUndef()) {
|
2009-08-28 06:17:37 +08:00
|
|
|
MakeNode(Dst, B, Pred, state->BindExpr(B, X));
|
2008-02-27 03:40:44 +08:00
|
|
|
return;
|
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-09-12 06:07:28 +08:00
|
|
|
DefinedOrUnknownSVal XD = cast<DefinedOrUnknownSVal>(X);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-27 03:05:15 +08:00
|
|
|
// We took the RHS. Because the value of the '&&' or '||' expression must
|
|
|
|
// evaluate to 0 or 1, we must assume the value of the RHS evaluates to 0
|
|
|
|
// or 1. Alternatively, we could take a lazy approach, and calculate this
|
|
|
|
// value later when necessary. We don't have the machinery in place for
|
|
|
|
// this right now, and since most logical expressions are used for branches,
|
2009-09-09 23:08:12 +08:00
|
|
|
// the payoff is not likely to be large. Instead, we do eager evaluation.
|
2009-09-12 06:07:28 +08:00
|
|
|
if (const GRState *newState = state->Assume(XD, true))
|
2009-09-09 23:08:12 +08:00
|
|
|
MakeNode(Dst, B, Pred,
|
2009-08-28 06:17:37 +08:00
|
|
|
newState->BindExpr(B, ValMgr.makeIntVal(1U, B->getType())));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-12 06:07:28 +08:00
|
|
|
if (const GRState *newState = state->Assume(XD, false))
|
2009-09-09 23:08:12 +08:00
|
|
|
MakeNode(Dst, B, Pred,
|
2009-08-28 06:17:37 +08:00
|
|
|
newState->BindExpr(B, ValMgr.makeIntVal(0U, B->getType())));
|
2008-02-05 08:26:40 +08:00
|
|
|
}
|
|
|
|
else {
|
2008-02-27 03:05:15 +08:00
|
|
|
// We took the LHS expression. Depending on whether we are '&&' or
|
|
|
|
// '||' we know what the value of the expression is via properties of
|
|
|
|
// the short-circuiting.
|
2009-09-09 23:08:12 +08:00
|
|
|
X = ValMgr.makeIntVal(B->getOpcode() == BinaryOperator::LAnd ? 0U : 1U,
|
2009-06-23 17:02:15 +08:00
|
|
|
B->getType());
|
2009-08-28 06:17:37 +08:00
|
|
|
MakeNode(Dst, B, Pred, state->BindExpr(B, X));
|
2008-02-27 03:05:15 +08:00
|
|
|
}
|
2008-01-30 07:32:35 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2008-04-17 02:39:06 +08:00
|
|
|
// Transfer functions: Loads and stores.
|
2008-04-16 07:06:53 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2008-01-16 07:55:06 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
|
2009-11-25 09:33:13 +08:00
|
|
|
ExplodedNodeSet &Dst) {
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-26 06:23:25 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-25 09:33:13 +08:00
|
|
|
CanQualType T = getContext().getCanonicalType(BE->getType());
|
2009-11-26 07:53:07 +08:00
|
|
|
SVal V = ValMgr.getBlockPointer(BE->getBlockDecl(), T,
|
|
|
|
Pred->getLocationContext());
|
|
|
|
|
2009-11-26 06:23:25 +08:00
|
|
|
MakeNode(Tmp, BE, Pred, GetState(Pred)->BindExpr(BE, V),
|
2009-11-25 09:33:13 +08:00
|
|
|
ProgramPoint::PostLValueKind);
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-26 06:23:25 +08:00
|
|
|
// Post-visit the BlockExpr.
|
|
|
|
CheckerVisit(BE, Dst, Tmp, false);
|
2009-11-25 09:33:13 +08:00
|
|
|
}
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitDeclRefExpr(const DeclRefExpr *Ex, ExplodedNode *Pred,
|
2009-08-22 06:28:32 +08:00
|
|
|
ExplodedNodeSet &Dst, bool asLValue) {
|
2009-12-08 06:05:27 +08:00
|
|
|
VisitCommonDeclRefExpr(Ex, Ex->getDecl(), Pred, Dst, asLValue);
|
|
|
|
}
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitBlockDeclRefExpr(const BlockDeclRefExpr *Ex,
|
2009-12-08 06:05:27 +08:00
|
|
|
ExplodedNode *Pred,
|
|
|
|
ExplodedNodeSet &Dst, bool asLValue) {
|
|
|
|
VisitCommonDeclRefExpr(Ex, Ex->getDecl(), Pred, Dst, asLValue);
|
|
|
|
}
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
|
2009-12-08 06:05:27 +08:00
|
|
|
ExplodedNode *Pred,
|
|
|
|
ExplodedNodeSet &Dst, bool asLValue) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-12 06:07:28 +08:00
|
|
|
const GRState *state = GetState(Pred);
|
2008-10-16 14:09:51 +08:00
|
|
|
|
|
|
|
if (const VarDecl* VD = dyn_cast<VarDecl>(D)) {
|
|
|
|
|
2009-08-22 06:28:32 +08:00
|
|
|
SVal V = state->getLValue(VD, Pred->getLocationContext());
|
2008-10-17 10:20:14 +08:00
|
|
|
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
if (asLValue) {
|
|
|
|
// For references, the 'lvalue' is the pointer address stored in the
|
|
|
|
// reference region.
|
|
|
|
if (VD->getType()->isReferenceType()) {
|
|
|
|
if (const MemRegion *R = V.getAsRegion())
|
2010-02-09 00:18:51 +08:00
|
|
|
V = state->getSVal(R);
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
else
|
|
|
|
V = UnknownVal();
|
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-25 17:44:02 +08:00
|
|
|
MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V),
|
|
|
|
ProgramPoint::PostLValueKind);
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
}
|
2008-10-16 14:09:51 +08:00
|
|
|
else
|
2009-02-13 09:45:31 +08:00
|
|
|
EvalLoad(Dst, Ex, Pred, state, V);
|
2008-10-16 14:09:51 +08:00
|
|
|
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
return;
|
2008-10-16 14:09:51 +08:00
|
|
|
} else if (const EnumConstantDecl* ED = dyn_cast<EnumConstantDecl>(D)) {
|
|
|
|
assert(!asLValue && "EnumConstantDecl does not have lvalue.");
|
|
|
|
|
2009-06-23 14:13:19 +08:00
|
|
|
SVal V = ValMgr.makeIntVal(ED->getInitVal());
|
2009-08-28 06:17:37 +08:00
|
|
|
MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V));
|
2008-10-16 14:09:51 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
} else if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D)) {
|
2009-09-23 09:30:01 +08:00
|
|
|
// This code is valid regardless of the value of 'isLValue'.
|
2009-04-20 13:24:46 +08:00
|
|
|
SVal V = ValMgr.getFunctionPointer(FD);
|
2009-08-28 06:17:37 +08:00
|
|
|
MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V),
|
2009-05-08 02:27:16 +08:00
|
|
|
ProgramPoint::PostLValueKind);
|
2008-10-16 14:09:51 +08:00
|
|
|
return;
|
2008-04-30 05:04:26 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-16 14:09:51 +08:00
|
|
|
assert (false &&
|
|
|
|
"ValueDecl support for this ValueDecl not implemented.");
|
2008-02-07 12:16:04 +08:00
|
|
|
}
|
|
|
|
|
2008-04-22 12:56:29 +08:00
|
|
|
/// VisitArraySubscriptExpr - Transfer function for array accesses
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitArraySubscriptExpr(const ArraySubscriptExpr* A,
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNode* Pred,
|
|
|
|
ExplodedNodeSet& Dst, bool asLValue){
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
const Expr* Base = A->getBase()->IgnoreParens();
|
|
|
|
const Expr* Idx = A->getIdx()->IgnoreParens();
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-24 10:23:11 +08:00
|
|
|
if (Base->getType()->isVectorType()) {
|
|
|
|
// For vector types get its lvalue.
|
|
|
|
// FIXME: This may not be correct. Is the rvalue of a vector its location?
|
|
|
|
// In fact, I think this is just a hack. We need to get the right
|
|
|
|
// semantics.
|
|
|
|
VisitLValue(Base, Pred, Tmp);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
else
|
2009-02-24 10:23:11 +08:00
|
|
|
Visit(Base, Pred, Tmp); // Get Base's rvalue, which should be an LocVal.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
for (ExplodedNodeSet::iterator I1=Tmp.begin(), E1=Tmp.end(); I1!=E1; ++I1) {
|
|
|
|
ExplodedNodeSet Tmp2;
|
2008-10-17 08:51:01 +08:00
|
|
|
Visit(Idx, *I1, Tmp2); // Evaluate the index.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-11 21:42:54 +08:00
|
|
|
ExplodedNodeSet Tmp3;
|
|
|
|
CheckerVisit(A, Tmp3, Tmp2, true);
|
|
|
|
|
|
|
|
for (ExplodedNodeSet::iterator I2=Tmp3.begin(),E2=Tmp3.end();I2!=E2; ++I2) {
|
2009-02-13 09:45:31 +08:00
|
|
|
const GRState* state = GetState(*I2);
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal V = state->getLValue(A->getType(), state->getSVal(Idx),
|
|
|
|
state->getSVal(Base));
|
2008-04-30 07:24:44 +08:00
|
|
|
|
2008-10-16 14:09:51 +08:00
|
|
|
if (asLValue)
|
2009-08-28 06:17:37 +08:00
|
|
|
MakeNode(Dst, A, *I2, state->BindExpr(A, V),
|
2009-05-08 02:27:16 +08:00
|
|
|
ProgramPoint::PostLValueKind);
|
2008-04-30 07:24:44 +08:00
|
|
|
else
|
2009-02-13 09:45:31 +08:00
|
|
|
EvalLoad(Dst, A, *I2, state, V);
|
2008-04-30 07:24:44 +08:00
|
|
|
}
|
2008-04-30 05:04:26 +08:00
|
|
|
}
|
2008-04-22 12:56:29 +08:00
|
|
|
}
|
|
|
|
|
2008-04-22 07:43:38 +08:00
|
|
|
/// VisitMemberExpr - Transfer function for member expressions.
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitMemberExpr(const MemberExpr* M, ExplodedNode* Pred,
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet& Dst, bool asLValue) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-22 07:43:38 +08:00
|
|
|
Expr* Base = M->getBase()->IgnoreParens();
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
if (M->isArrow())
|
2008-10-18 11:28:48 +08:00
|
|
|
Visit(Base, Pred, Tmp); // p->f = ... or ... = p->f
|
|
|
|
else
|
|
|
|
VisitLValue(Base, Pred, Tmp); // x.f = ... or ... = x.f
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-12-21 07:49:58 +08:00
|
|
|
FieldDecl *Field = dyn_cast<FieldDecl>(M->getMemberDecl());
|
|
|
|
if (!Field) // FIXME: skipping member expressions for non-fields
|
|
|
|
return;
|
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
|
2009-02-13 09:45:31 +08:00
|
|
|
const GRState* state = GetState(*I);
|
2008-10-17 08:51:01 +08:00
|
|
|
// FIXME: Should we insert some assumption logic in here to determine
|
|
|
|
// if "Base" is a valid piece of memory? Before we put this assumption
|
2008-12-21 07:49:58 +08:00
|
|
|
// later when using FieldOffset lvals (which we no longer have).
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal L = state->getLValue(Field, state->getSVal(Base));
|
2008-10-17 08:51:01 +08:00
|
|
|
|
2009-10-30 15:19:39 +08:00
|
|
|
if (asLValue)
|
|
|
|
MakeNode(Dst, M, *I, state->BindExpr(M, L), ProgramPoint::PostLValueKind);
|
|
|
|
else
|
|
|
|
EvalLoad(Dst, M, *I, state, L);
|
2008-04-22 07:43:38 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-13 09:45:31 +08:00
|
|
|
/// EvalBind - Handle the semantics of binding a value to a specific location.
|
|
|
|
/// This method is used by EvalStore and (soon) VisitDeclStmt, and others.
|
2010-07-20 10:41:28 +08:00
|
|
|
void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, const Stmt *AssignE,
|
|
|
|
const Stmt* StoreE, ExplodedNode* Pred,
|
2009-11-04 08:09:15 +08:00
|
|
|
const GRState* state, SVal location, SVal Val,
|
|
|
|
bool atDeclInit) {
|
2010-02-16 07:02:46 +08:00
|
|
|
|
|
|
|
|
2009-11-04 12:24:16 +08:00
|
|
|
// Do a previsit of the bind.
|
|
|
|
ExplodedNodeSet CheckedSet, Src;
|
|
|
|
Src.Add(Pred);
|
2009-11-05 08:42:23 +08:00
|
|
|
CheckerVisitBind(AssignE, StoreE, CheckedSet, Src, location, Val, true);
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-04 12:24:16 +08:00
|
|
|
for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
|
|
|
|
I!=E; ++I) {
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-04 12:24:16 +08:00
|
|
|
if (Pred != *I)
|
|
|
|
state = GetState(*I);
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-04 12:24:16 +08:00
|
|
|
const GRState* newState = 0;
|
2009-02-13 09:45:31 +08:00
|
|
|
|
2009-11-04 12:24:16 +08:00
|
|
|
if (atDeclInit) {
|
|
|
|
const VarRegion *VR =
|
|
|
|
cast<VarRegion>(cast<loc::MemRegionVal>(location).getRegion());
|
2009-11-04 08:09:15 +08:00
|
|
|
|
2009-11-04 12:24:16 +08:00
|
|
|
newState = state->bindDecl(VR, Val);
|
2009-11-04 08:09:15 +08:00
|
|
|
}
|
|
|
|
else {
|
2009-11-04 12:24:16 +08:00
|
|
|
if (location.isUnknown()) {
|
|
|
|
// We know that the new state will be the same as the old state since
|
|
|
|
// the location of the binding is "unknown". Consequently, there
|
|
|
|
// is no reason to just create a new node.
|
|
|
|
newState = state;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// We are binding to a value other than 'unknown'. Perform the binding
|
|
|
|
// using the StoreManager.
|
|
|
|
newState = state->bindLoc(cast<Loc>(location), Val);
|
|
|
|
}
|
2009-11-04 08:09:15 +08:00
|
|
|
}
|
2009-02-13 09:45:31 +08:00
|
|
|
|
2009-11-04 12:24:16 +08:00
|
|
|
// The next thing to do is check if the GRTransferFuncs object wants to
|
|
|
|
// update the state based on the new binding. If the GRTransferFunc object
|
|
|
|
// doesn't do anything, just auto-propagate the current state.
|
2009-11-05 08:42:23 +08:00
|
|
|
GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, newState, StoreE,
|
2009-11-04 12:24:16 +08:00
|
|
|
newState != state);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-04 12:24:16 +08:00
|
|
|
getTF().EvalBind(BuilderRef, location, Val);
|
|
|
|
}
|
2009-02-13 09:45:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// EvalStore - Handle the semantics of a store via an assignment.
|
|
|
|
/// @param Dst The node set to store generated state nodes
|
|
|
|
/// @param Ex The expression representing the location of the store
|
|
|
|
/// @param state The current simulation state
|
|
|
|
/// @param location The location to store the value
|
|
|
|
/// @param Val The value to be stored
|
2010-07-20 10:41:28 +08:00
|
|
|
void GRExprEngine::EvalStore(ExplodedNodeSet& Dst, const Expr *AssignE,
|
|
|
|
const Expr* StoreE,
|
2009-11-05 08:42:23 +08:00
|
|
|
ExplodedNode* Pred,
|
2009-04-11 08:11:10 +08:00
|
|
|
const GRState* state, SVal location, SVal Val,
|
|
|
|
const void *tag) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-05 08:42:23 +08:00
|
|
|
assert(Builder && "GRStmtNodeBuilder must be defined.");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
// Evaluate the location (checks for bad dereferences).
|
2009-11-11 11:26:34 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
|
|
|
EvalLocation(Tmp, StoreE, Pred, state, location, tag, false);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-11 11:26:34 +08:00
|
|
|
if (Tmp.empty())
|
2008-04-30 05:04:26 +08:00
|
|
|
return;
|
2008-04-19 04:35:30 +08:00
|
|
|
|
2009-11-11 11:26:34 +08:00
|
|
|
assert(!location.isUndef());
|
2009-02-13 09:45:31 +08:00
|
|
|
|
2009-11-11 11:26:34 +08:00
|
|
|
SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind,
|
|
|
|
ProgramPoint::PostStoreKind);
|
|
|
|
SaveAndRestore<const void*> OldTag(Builder->Tag, tag);
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
// Proceed with the store.
|
2009-11-11 11:26:34 +08:00
|
|
|
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
|
|
|
|
EvalBind(Dst, AssignE, StoreE, *NI, GetState(*NI), location, Val);
|
2008-04-30 05:04:26 +08:00
|
|
|
}
|
|
|
|
|
2010-07-20 10:41:28 +08:00
|
|
|
void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, const Expr *Ex,
|
|
|
|
ExplodedNode* Pred,
|
2009-04-11 08:11:10 +08:00
|
|
|
const GRState* state, SVal location,
|
2009-11-16 12:49:44 +08:00
|
|
|
const void *tag, QualType LoadTy) {
|
2008-04-30 05:04:26 +08:00
|
|
|
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
// Are we loading from a region? This actually results in two loads; one
|
|
|
|
// to fetch the address of the referenced value and one to fetch the
|
|
|
|
// referenced value.
|
2010-02-16 07:02:46 +08:00
|
|
|
if (const TypedRegion *TR =
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
|
2010-02-16 07:02:46 +08:00
|
|
|
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
QualType ValTy = TR->getValueType(getContext());
|
|
|
|
if (const ReferenceType *RT = ValTy->getAs<ReferenceType>()) {
|
2010-02-16 07:02:46 +08:00
|
|
|
static int loadReferenceTag = 0;
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
|
|
|
EvalLoadCommon(Tmp, Ex, Pred, state, location, &loadReferenceTag,
|
|
|
|
getContext().getPointerType(RT->getPointeeType()));
|
|
|
|
|
|
|
|
// Perform the load from the referenced value.
|
|
|
|
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end() ; I!=E; ++I) {
|
|
|
|
state = GetState(*I);
|
2010-02-09 00:18:51 +08:00
|
|
|
location = state->getSVal(Ex);
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
EvalLoadCommon(Dst, Ex, *I, state, location, tag, LoadTy);
|
2010-02-16 07:02:46 +08:00
|
|
|
}
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
EvalLoadCommon(Dst, Ex, Pred, state, location, tag, LoadTy);
|
|
|
|
}
|
|
|
|
|
2010-07-20 10:41:28 +08:00
|
|
|
void GRExprEngine::EvalLoadCommon(ExplodedNodeSet& Dst, const Expr *Ex,
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
ExplodedNode* Pred,
|
|
|
|
const GRState* state, SVal location,
|
|
|
|
const void *tag, QualType LoadTy) {
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
// Evaluate the location (checks for bad dereferences).
|
2009-11-11 11:26:34 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
|
|
|
EvalLocation(Tmp, Ex, Pred, state, location, tag, true);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-11 11:26:34 +08:00
|
|
|
if (Tmp.empty())
|
2008-04-30 05:04:26 +08:00
|
|
|
return;
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-11 11:26:34 +08:00
|
|
|
assert(!location.isUndef());
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-11 11:26:34 +08:00
|
|
|
SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind);
|
|
|
|
SaveAndRestore<const void*> OldTag(Builder->Tag);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
// Proceed with the load.
|
2009-11-11 11:26:34 +08:00
|
|
|
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
|
|
|
|
state = GetState(*NI);
|
|
|
|
if (location.isUnknown()) {
|
|
|
|
// This is important. We must nuke the old binding.
|
|
|
|
MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, UnknownVal()),
|
|
|
|
ProgramPoint::PostLoadKind, tag);
|
|
|
|
}
|
|
|
|
else {
|
2010-02-16 07:02:46 +08:00
|
|
|
SVal V = state->getSVal(cast<Loc>(location), LoadTy.isNull() ?
|
2009-11-16 12:49:44 +08:00
|
|
|
Ex->getType() : LoadTy);
|
2009-11-11 11:26:34 +08:00
|
|
|
MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, V), ProgramPoint::PostLoadKind,
|
|
|
|
tag);
|
|
|
|
}
|
2008-11-28 16:34:30 +08:00
|
|
|
}
|
2008-04-30 05:04:26 +08:00
|
|
|
}
|
|
|
|
|
2010-07-20 10:41:28 +08:00
|
|
|
void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, const Stmt *S,
|
2009-11-11 11:26:34 +08:00
|
|
|
ExplodedNode* Pred,
|
|
|
|
const GRState* state, SVal location,
|
|
|
|
const void *tag, bool isLoad) {
|
2009-11-20 11:50:46 +08:00
|
|
|
// Early checks for performance reason.
|
|
|
|
if (location.isUnknown() || Checkers.empty()) {
|
2009-11-11 11:26:34 +08:00
|
|
|
Dst.Add(Pred);
|
|
|
|
return;
|
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-11 11:26:34 +08:00
|
|
|
ExplodedNodeSet Src, Tmp;
|
|
|
|
Src.Add(Pred);
|
|
|
|
ExplodedNodeSet *PrevSet = &Src;
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-11 11:26:34 +08:00
|
|
|
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
|
2009-11-03 07:19:29 +08:00
|
|
|
{
|
2009-12-09 10:45:41 +08:00
|
|
|
ExplodedNodeSet *CurrSet = 0;
|
|
|
|
if (I+1 == E)
|
|
|
|
CurrSet = &Dst;
|
|
|
|
else {
|
|
|
|
CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
|
|
|
|
CurrSet->clear();
|
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-11 11:26:34 +08:00
|
|
|
void *tag = I->first;
|
|
|
|
Checker *checker = I->second;
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-11 11:26:34 +08:00
|
|
|
for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
|
2009-11-24 06:22:01 +08:00
|
|
|
NI != NE; ++NI) {
|
|
|
|
// Use the 'state' argument only when the predecessor node is the
|
|
|
|
// same as Pred. This allows us to catch updates to the state.
|
|
|
|
checker->GR_VisitLocation(*CurrSet, *Builder, *this, S, *NI,
|
|
|
|
*NI == Pred ? state : GetState(*NI),
|
2009-11-11 11:26:34 +08:00
|
|
|
location, tag, isLoad);
|
2009-11-24 06:22:01 +08:00
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-11 11:26:34 +08:00
|
|
|
// Update which NodeSet is the current one.
|
|
|
|
PrevSet = CurrSet;
|
2009-11-03 07:19:29 +08:00
|
|
|
}
|
2008-04-17 02:39:06 +08:00
|
|
|
}
|
|
|
|
|
2010-05-06 11:38:27 +08:00
|
|
|
bool GRExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE,
|
|
|
|
ExplodedNode *Pred) {
|
|
|
|
const GRState *state = GetState(Pred);
|
|
|
|
const Expr *Callee = CE->getCallee();
|
|
|
|
SVal L = state->getSVal(Callee);
|
|
|
|
|
|
|
|
const FunctionDecl *FD = L.getAsFunctionDecl();
|
|
|
|
if (!FD)
|
|
|
|
return false;
|
|
|
|
|
2010-07-19 09:31:21 +08:00
|
|
|
// Check if the function definition is in the same translation unit.
|
|
|
|
if (FD->hasBody(FD)) {
|
|
|
|
// Now we have the definition of the callee, create a CallEnter node.
|
|
|
|
CallEnter Loc(CE, AMgr.getAnalysisContext(FD), Pred->getLocationContext());
|
|
|
|
|
|
|
|
ExplodedNode *N = Builder->generateNode(Loc, state, Pred);
|
|
|
|
Dst.Add(N);
|
|
|
|
return true;
|
|
|
|
}
|
2010-05-06 11:38:27 +08:00
|
|
|
|
2010-07-19 09:31:21 +08:00
|
|
|
// Check if we can find the function definition in other translation units.
|
|
|
|
if (AMgr.hasIndexer()) {
|
|
|
|
const AnalysisContext *C = AMgr.getAnalysisContextInAnotherTU(FD);
|
|
|
|
if (C == 0)
|
|
|
|
return false;
|
2010-05-06 11:38:27 +08:00
|
|
|
|
2010-07-19 09:31:21 +08:00
|
|
|
CallEnter Loc(CE, C, Pred->getLocationContext());
|
|
|
|
ExplodedNode *N = Builder->generateNode(Loc, state, Pred);
|
2010-05-06 11:38:27 +08:00
|
|
|
Dst.Add(N);
|
2010-07-19 09:31:21 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2010-05-06 11:38:27 +08:00
|
|
|
}
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitCall(const CallExpr* CE, ExplodedNode* Pred,
|
|
|
|
CallExpr::const_arg_iterator AI,
|
|
|
|
CallExpr::const_arg_iterator AE,
|
2009-12-19 04:13:39 +08:00
|
|
|
ExplodedNodeSet& Dst, bool asLValue) {
|
2009-12-18 04:06:29 +08:00
|
|
|
|
2008-10-28 08:22:11 +08:00
|
|
|
// Determine the type of function we're calling (if available).
|
2009-02-27 07:50:07 +08:00
|
|
|
const FunctionProtoType *Proto = NULL;
|
2008-10-28 08:22:11 +08:00
|
|
|
QualType FnType = CE->getCallee()->IgnoreParens()->getType();
|
2009-07-30 05:53:49 +08:00
|
|
|
if (const PointerType *FnTypePtr = FnType->getAs<PointerType>())
|
2009-09-22 07:43:11 +08:00
|
|
|
Proto = FnTypePtr->getPointeeType()->getAs<FunctionProtoType>();
|
2008-10-28 08:22:11 +08:00
|
|
|
|
2009-12-18 04:06:29 +08:00
|
|
|
// Create a worklist to process the arguments.
|
|
|
|
llvm::SmallVector<CallExprWLItem, 20> WorkList;
|
|
|
|
WorkList.reserve(AE - AI);
|
|
|
|
WorkList.push_back(CallExprWLItem(AI, Pred));
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-18 04:06:29 +08:00
|
|
|
ExplodedNodeSet ArgsEvaluated;
|
2009-12-19 04:13:39 +08:00
|
|
|
|
2009-12-18 04:06:29 +08:00
|
|
|
while (!WorkList.empty()) {
|
|
|
|
CallExprWLItem Item = WorkList.back();
|
|
|
|
WorkList.pop_back();
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-18 04:06:29 +08:00
|
|
|
if (Item.I == AE) {
|
|
|
|
ArgsEvaluated.insert(Item.N);
|
|
|
|
continue;
|
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-18 04:06:29 +08:00
|
|
|
// Evaluate the argument.
|
|
|
|
ExplodedNodeSet Tmp;
|
|
|
|
const unsigned ParamIdx = Item.I - AI;
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2008-10-28 08:22:11 +08:00
|
|
|
bool VisitAsLvalue = false;
|
|
|
|
if (Proto && ParamIdx < Proto->getNumArgs())
|
|
|
|
VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType();
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2008-10-28 08:22:11 +08:00
|
|
|
if (VisitAsLvalue)
|
2009-12-18 04:06:29 +08:00
|
|
|
VisitLValue(*Item.I, Item.N, Tmp);
|
2008-10-28 08:22:11 +08:00
|
|
|
else
|
2009-12-18 04:06:29 +08:00
|
|
|
Visit(*Item.I, Item.N, Tmp);
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-18 04:06:29 +08:00
|
|
|
// Enqueue evaluating the next argument on the worklist.
|
|
|
|
++(Item.I);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-12-18 04:06:29 +08:00
|
|
|
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
|
|
|
|
WorkList.push_back(CallExprWLItem(Item.I, *NI));
|
2008-02-19 09:44:53 +08:00
|
|
|
}
|
|
|
|
|
2009-12-18 04:10:17 +08:00
|
|
|
// Now process the call itself.
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet DstTmp;
|
2010-07-20 14:22:24 +08:00
|
|
|
const Expr* Callee = CE->getCallee()->IgnoreParens();
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-18 04:06:29 +08:00
|
|
|
for (ExplodedNodeSet::iterator NI=ArgsEvaluated.begin(),
|
2009-12-18 04:10:17 +08:00
|
|
|
NE=ArgsEvaluated.end(); NI != NE; ++NI) {
|
|
|
|
// Evaluate the callee.
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet DstTmp2;
|
2010-02-16 07:02:46 +08:00
|
|
|
Visit(Callee, *NI, DstTmp2);
|
2009-07-23 05:43:51 +08:00
|
|
|
// Perform the previsit of the CallExpr, storing the results in DstTmp.
|
|
|
|
CheckerVisit(CE, DstTmp, DstTmp2, true);
|
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-18 04:06:29 +08:00
|
|
|
// Finally, evaluate the function call. We try each of the checkers
|
|
|
|
// to see if the can evaluate the function call.
|
2009-12-09 10:45:41 +08:00
|
|
|
ExplodedNodeSet DstTmp3;
|
2009-12-19 04:13:39 +08:00
|
|
|
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
|
2009-09-05 13:00:57 +08:00
|
|
|
DI != DE; ++DI) {
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-02-13 09:45:31 +08:00
|
|
|
const GRState* state = GetState(*DI);
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal L = state->getSVal(Callee);
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2008-03-04 00:47:31 +08:00
|
|
|
// FIXME: Add support for symbolic function calls (calls involving
|
|
|
|
// function pointer values that are symbolic).
|
2008-03-06 05:15:02 +08:00
|
|
|
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
|
2009-12-09 10:45:41 +08:00
|
|
|
ExplodedNodeSet DstChecker;
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-07 17:17:35 +08:00
|
|
|
// If the callee is processed by a checker, skip the rest logic.
|
|
|
|
if (CheckerEvalCall(CE, DstChecker, *DI))
|
2009-12-09 13:48:53 +08:00
|
|
|
DstTmp3.insert(DstChecker);
|
2010-05-06 11:38:27 +08:00
|
|
|
else if (AMgr.shouldInlineCall() && InlineCall(Dst, CE, *DI)) {
|
|
|
|
// Callee is inlined. We shouldn't do post call checking.
|
|
|
|
return;
|
|
|
|
}
|
2009-12-07 17:17:35 +08:00
|
|
|
else {
|
2009-12-09 10:45:41 +08:00
|
|
|
for (ExplodedNodeSet::iterator DI_Checker = DstChecker.begin(),
|
2009-12-18 04:06:29 +08:00
|
|
|
DE_Checker = DstChecker.end();
|
|
|
|
DI_Checker != DE_Checker; ++DI_Checker) {
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-18 04:06:29 +08:00
|
|
|
// Dispatch to the plug-in transfer function.
|
2009-12-09 10:45:41 +08:00
|
|
|
unsigned OldSize = DstTmp3.size();
|
|
|
|
SaveOr OldHasGen(Builder->HasGeneratedNode);
|
|
|
|
Pred = *DI_Checker;
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-09 10:45:41 +08:00
|
|
|
// Dispatch to transfer function logic to handle the call itself.
|
|
|
|
// FIXME: Allow us to chain together transfer functions.
|
2010-02-16 07:02:46 +08:00
|
|
|
assert(Builder && "GRStmtNodeBuilder must be defined.");
|
2009-12-09 20:23:28 +08:00
|
|
|
getTF().EvalCall(DstTmp3, *this, *Builder, CE, L, Pred);
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-09 10:45:41 +08:00
|
|
|
// Handle the case where no nodes where generated. Auto-generate that
|
|
|
|
// contains the updated state if we aren't generating sinks.
|
|
|
|
if (!Builder->BuildSinks && DstTmp3.size() == OldSize &&
|
|
|
|
!Builder->HasGeneratedNode)
|
|
|
|
MakeNode(DstTmp3, CE, Pred, state);
|
|
|
|
}
|
2009-12-07 17:17:35 +08:00
|
|
|
}
|
2008-04-16 07:06:53 +08:00
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-18 04:06:29 +08:00
|
|
|
// Finally, perform the post-condition check of the CallExpr and store
|
|
|
|
// the created nodes in 'Dst'.
|
2010-06-03 14:19:01 +08:00
|
|
|
// If the callee returns a reference and we want an rvalue, skip this check
|
|
|
|
// and do the load.
|
2009-12-19 04:13:39 +08:00
|
|
|
if (!(!asLValue && CalleeReturnsReference(CE))) {
|
|
|
|
CheckerVisit(CE, Dst, DstTmp3, false);
|
|
|
|
return;
|
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-19 04:13:39 +08:00
|
|
|
// Handle the case where the called function returns a reference but
|
|
|
|
// we expect an rvalue. For such cases, convert the reference to
|
2010-02-16 07:02:46 +08:00
|
|
|
// an rvalue.
|
2009-12-19 04:13:39 +08:00
|
|
|
// FIXME: This conversion doesn't actually happen unless the result
|
|
|
|
// of CallExpr is consumed by another expression.
|
|
|
|
ExplodedNodeSet DstTmp4;
|
|
|
|
CheckerVisit(CE, DstTmp4, DstTmp3, false);
|
|
|
|
QualType LoadTy = CE->getType();
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-19 04:13:39 +08:00
|
|
|
static int *ConvertToRvalueTag = 0;
|
|
|
|
for (ExplodedNodeSet::iterator NI = DstTmp4.begin(), NE = DstTmp4.end();
|
|
|
|
NI!=NE; ++NI) {
|
|
|
|
const GRState *state = GetState(*NI);
|
2010-02-09 00:18:51 +08:00
|
|
|
EvalLoad(Dst, CE, *NI, state, state->getSVal(CE),
|
2009-12-19 04:13:39 +08:00
|
|
|
&ConvertToRvalueTag, LoadTy);
|
|
|
|
}
|
2008-04-16 07:06:53 +08:00
|
|
|
}
|
|
|
|
|
2008-10-17 08:03:18 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Transfer function: Objective-C ivar references.
|
|
|
|
//===----------------------------------------------------------------------===//
|
2009-02-26 06:32:02 +08:00
|
|
|
|
2009-03-01 04:50:43 +08:00
|
|
|
static std::pair<const void*,const void*> EagerlyAssumeTag
|
2010-05-11 14:18:17 +08:00
|
|
|
= std::pair<const void*,const void*>(&EagerlyAssumeTag,static_cast<void*>(0));
|
2009-03-01 04:50:43 +08:00
|
|
|
|
2009-09-10 13:44:00 +08:00
|
|
|
void GRExprEngine::EvalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
|
2010-07-20 14:22:24 +08:00
|
|
|
const Expr *Ex) {
|
2009-08-06 20:48:26 +08:00
|
|
|
for (ExplodedNodeSet::iterator I=Src.begin(), E=Src.end(); I!=E; ++I) {
|
|
|
|
ExplodedNode *Pred = *I;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-26 07:32:10 +08:00
|
|
|
// Test if the previous node was as the same expression. This can happen
|
|
|
|
// when the expression fails to evaluate to anything meaningful and
|
|
|
|
// (as an optimization) we don't generate a node.
|
2009-09-09 23:08:12 +08:00
|
|
|
ProgramPoint P = Pred->getLocation();
|
2009-02-26 07:32:10 +08:00
|
|
|
if (!isa<PostStmt>(P) || cast<PostStmt>(P).getStmt() != Ex) {
|
2009-09-09 23:08:12 +08:00
|
|
|
Dst.Add(Pred);
|
2009-02-26 07:32:10 +08:00
|
|
|
continue;
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2009-02-26 07:32:10 +08:00
|
|
|
|
2010-04-20 12:53:09 +08:00
|
|
|
const GRState* state = GetState(Pred);
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal V = state->getSVal(Ex);
|
2009-09-12 06:07:28 +08:00
|
|
|
if (nonloc::SymExprVal *SEV = dyn_cast<nonloc::SymExprVal>(&V)) {
|
2009-02-26 06:32:02 +08:00
|
|
|
// First assume that the condition is true.
|
2009-09-12 06:07:28 +08:00
|
|
|
if (const GRState *stateTrue = state->Assume(*SEV, true)) {
|
2009-09-09 23:08:12 +08:00
|
|
|
stateTrue = stateTrue->BindExpr(Ex,
|
2009-08-27 09:39:13 +08:00
|
|
|
ValMgr.makeIntVal(1U, Ex->getType()));
|
2009-09-09 23:08:12 +08:00
|
|
|
Dst.Add(Builder->generateNode(PostStmtCustom(Ex,
|
2009-08-15 11:17:38 +08:00
|
|
|
&EagerlyAssumeTag, Pred->getLocationContext()),
|
2009-02-26 06:32:02 +08:00
|
|
|
stateTrue, Pred));
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-26 06:32:02 +08:00
|
|
|
// Next, assume that the condition is false.
|
2009-09-12 06:07:28 +08:00
|
|
|
if (const GRState *stateFalse = state->Assume(*SEV, false)) {
|
2009-09-09 23:08:12 +08:00
|
|
|
stateFalse = stateFalse->BindExpr(Ex,
|
2009-08-27 09:39:13 +08:00
|
|
|
ValMgr.makeIntVal(0U, Ex->getType()));
|
2009-08-15 11:17:38 +08:00
|
|
|
Dst.Add(Builder->generateNode(PostStmtCustom(Ex, &EagerlyAssumeTag,
|
|
|
|
Pred->getLocationContext()),
|
2009-02-26 06:32:02 +08:00
|
|
|
stateFalse, Pred));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Dst.Add(Pred);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Transfer function: Objective-C ivar references.
|
|
|
|
//===----------------------------------------------------------------------===//
|
2008-10-17 08:03:18 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitObjCIvarRefExpr(const ObjCIvarRefExpr* Ex,
|
|
|
|
ExplodedNode* Pred,
|
2009-09-10 13:44:00 +08:00
|
|
|
ExplodedNodeSet& Dst, bool asLValue) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
const Expr* Base = cast<Expr>(Ex->getBase());
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
2008-10-17 08:03:18 +08:00
|
|
|
Visit(Base, Pred, Tmp);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
|
2009-02-13 09:45:31 +08:00
|
|
|
const GRState* state = GetState(*I);
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal BaseVal = state->getSVal(Base);
|
2009-06-20 01:10:32 +08:00
|
|
|
SVal location = state->getLValue(Ex->getDecl(), BaseVal);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-17 08:03:18 +08:00
|
|
|
if (asLValue)
|
2009-08-28 06:17:37 +08:00
|
|
|
MakeNode(Dst, Ex, *I, state->BindExpr(Ex, location));
|
2008-10-17 08:03:18 +08:00
|
|
|
else
|
2009-02-13 09:45:31 +08:00
|
|
|
EvalLoad(Dst, Ex, *I, state, location);
|
2008-10-17 08:03:18 +08:00
|
|
|
}
|
2008-11-13 03:24:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Transfer function: Objective-C fast enumeration 'for' statements.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt* S,
|
2009-09-10 13:44:00 +08:00
|
|
|
ExplodedNode* Pred, ExplodedNodeSet& Dst) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-11-13 03:24:17 +08:00
|
|
|
// ObjCForCollectionStmts are processed in two places. This method
|
|
|
|
// handles the case where an ObjCForCollectionStmt* occurs as one of the
|
|
|
|
// statements within a basic block. This transfer function does two things:
|
|
|
|
//
|
|
|
|
// (1) binds the next container value to 'element'. This creates a new
|
|
|
|
// node in the ExplodedGraph.
|
|
|
|
//
|
|
|
|
// (2) binds the value 0/1 to the ObjCForCollectionStmt* itself, indicating
|
|
|
|
// whether or not the container has any more elements. This value
|
|
|
|
// will be tested in ProcessBranch. We need to explicitly bind
|
|
|
|
// this value because a container can contain nil elements.
|
2009-09-09 23:08:12 +08:00
|
|
|
//
|
2008-11-13 03:24:17 +08:00
|
|
|
// FIXME: Eventually this logic should actually do dispatches to
|
|
|
|
// 'countByEnumeratingWithState:objects:count:' (NSFastEnumeration).
|
|
|
|
// This will require simulating a temporary NSFastEnumerationState, either
|
|
|
|
// through an SVal or through the use of MemRegions. This value can
|
|
|
|
// be affixed to the ObjCForCollectionStmt* instead of 0/1; when the loop
|
|
|
|
// terminates we reclaim the temporary (it goes out of scope) and we
|
|
|
|
// we can test if the SVal is 0 or if the MemRegion is null (depending
|
|
|
|
// on what approach we take).
|
|
|
|
//
|
|
|
|
// For now: simulate (1) by assigning either a symbol or nil if the
|
|
|
|
// container is empty. Thus this transfer function will by default
|
|
|
|
// result in state splitting.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
const Stmt* elem = S->getElement();
|
2008-11-15 03:47:18 +08:00
|
|
|
SVal ElementV;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
if (const DeclStmt* DS = dyn_cast<DeclStmt>(elem)) {
|
|
|
|
const VarDecl* ElemD = cast<VarDecl>(DS->getSingleDecl());
|
2008-11-13 03:24:17 +08:00
|
|
|
assert (ElemD->getInit() == 0);
|
2009-08-22 06:28:32 +08:00
|
|
|
ElementV = GetState(Pred)->getLValue(ElemD, Pred->getLocationContext());
|
2008-11-15 03:47:18 +08:00
|
|
|
VisitObjCForCollectionStmtAux(S, Pred, Dst, ElementV);
|
|
|
|
return;
|
2008-11-13 03:24:17 +08:00
|
|
|
}
|
2008-11-15 03:47:18 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
2008-11-15 03:47:18 +08:00
|
|
|
VisitLValue(cast<Expr>(elem), Pred, Tmp);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) {
|
2008-11-15 03:47:18 +08:00
|
|
|
const GRState* state = GetState(*I);
|
2010-02-09 00:18:51 +08:00
|
|
|
VisitObjCForCollectionStmtAux(S, *I, Dst, state->getSVal(elem));
|
2008-11-15 03:47:18 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitObjCForCollectionStmtAux(const ObjCForCollectionStmt* S,
|
2009-09-10 13:44:00 +08:00
|
|
|
ExplodedNode* Pred, ExplodedNodeSet& Dst,
|
2008-11-15 03:47:18 +08:00
|
|
|
SVal ElementV) {
|
|
|
|
|
2009-11-11 11:26:34 +08:00
|
|
|
// Check if the location we are writing back to is a null pointer.
|
2010-07-20 14:22:24 +08:00
|
|
|
const Stmt* elem = S->getElement();
|
2009-11-11 11:26:34 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
|
|
|
EvalLocation(Tmp, elem, Pred, GetState(Pred), ElementV, NULL, false);
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-11 11:26:34 +08:00
|
|
|
if (Tmp.empty())
|
2008-11-15 03:47:18 +08:00
|
|
|
return;
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-11 11:26:34 +08:00
|
|
|
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
|
|
|
|
Pred = *NI;
|
|
|
|
const GRState *state = GetState(Pred);
|
|
|
|
|
|
|
|
// Handle the case where the container still has elements.
|
|
|
|
SVal TrueV = ValMgr.makeTruthVal(1);
|
|
|
|
const GRState *hasElems = state->BindExpr(S, TrueV);
|
|
|
|
|
|
|
|
// Handle the case where the container has no elements.
|
|
|
|
SVal FalseV = ValMgr.makeTruthVal(0);
|
|
|
|
const GRState *noElems = state->BindExpr(S, FalseV);
|
|
|
|
|
|
|
|
if (loc::MemRegionVal* MV = dyn_cast<loc::MemRegionVal>(&ElementV))
|
|
|
|
if (const TypedRegion* R = dyn_cast<TypedRegion>(MV->getRegion())) {
|
|
|
|
// FIXME: The proper thing to do is to really iterate over the
|
|
|
|
// container. We will do this with dispatch logic to the store.
|
|
|
|
// For now, just 'conjure' up a symbolic value.
|
|
|
|
QualType T = R->getValueType(getContext());
|
|
|
|
assert(Loc::IsLocType(T));
|
|
|
|
unsigned Count = Builder->getCurrentBlockCount();
|
|
|
|
SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count);
|
|
|
|
SVal V = ValMgr.makeLoc(Sym);
|
|
|
|
hasElems = hasElems->bindLoc(ElementV, V);
|
|
|
|
|
|
|
|
// Bind the location to 'nil' on the false branch.
|
|
|
|
SVal nilV = ValMgr.makeIntVal(0, T);
|
|
|
|
noElems = noElems->bindLoc(ElementV, nilV);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-11 11:26:34 +08:00
|
|
|
// Create the new nodes.
|
|
|
|
MakeNode(Dst, S, Pred, hasElems);
|
|
|
|
MakeNode(Dst, S, Pred, noElems);
|
|
|
|
}
|
2008-10-17 08:03:18 +08:00
|
|
|
}
|
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Transfer function: Objective-C message expressions.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-02-16 07:02:46 +08:00
|
|
|
namespace {
|
|
|
|
class ObjCMsgWLItem {
|
|
|
|
public:
|
2010-07-20 14:22:24 +08:00
|
|
|
ObjCMessageExpr::const_arg_iterator I;
|
2010-02-16 07:02:46 +08:00
|
|
|
ExplodedNode *N;
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
ObjCMsgWLItem(const ObjCMessageExpr::const_arg_iterator &i, ExplodedNode *n)
|
2010-02-16 07:02:46 +08:00
|
|
|
: I(i), N(n) {}
|
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitObjCMessageExpr(const ObjCMessageExpr* ME,
|
|
|
|
ExplodedNode* Pred,
|
2009-12-23 06:13:46 +08:00
|
|
|
ExplodedNodeSet& Dst, bool asLValue){
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-02-16 07:02:46 +08:00
|
|
|
// Create a worklist to process both the arguments.
|
|
|
|
llvm::SmallVector<ObjCMsgWLItem, 20> WL;
|
2008-04-16 07:06:53 +08:00
|
|
|
|
2010-02-16 07:02:46 +08:00
|
|
|
// But first evaluate the receiver (if any).
|
2010-07-20 14:22:24 +08:00
|
|
|
ObjCMessageExpr::const_arg_iterator AI = ME->arg_begin(), AE = ME->arg_end();
|
|
|
|
if (const Expr *Receiver = ME->getInstanceReceiver()) {
|
2010-02-16 07:02:46 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
|
|
|
Visit(Receiver, Pred, Tmp);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-02-16 07:02:46 +08:00
|
|
|
if (Tmp.empty())
|
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-02-16 07:02:46 +08:00
|
|
|
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I)
|
|
|
|
WL.push_back(ObjCMsgWLItem(AI, *I));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
WL.push_back(ObjCMsgWLItem(AI, Pred));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-02-16 07:02:46 +08:00
|
|
|
// Evaluate the arguments.
|
|
|
|
ExplodedNodeSet ArgsEvaluated;
|
|
|
|
while (!WL.empty()) {
|
|
|
|
ObjCMsgWLItem Item = WL.back();
|
|
|
|
WL.pop_back();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-02-16 07:02:46 +08:00
|
|
|
if (Item.I == AE) {
|
|
|
|
ArgsEvaluated.insert(Item.N);
|
|
|
|
continue;
|
2008-04-16 07:06:53 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-02-16 07:02:46 +08:00
|
|
|
// Evaluate the subexpression.
|
|
|
|
ExplodedNodeSet Tmp;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-02-16 07:02:46 +08:00
|
|
|
// FIXME: [Objective-C++] handle arguments that are references
|
|
|
|
Visit(*Item.I, Item.N, Tmp);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-02-16 07:02:46 +08:00
|
|
|
// Enqueue evaluating the next argument on the worklist.
|
|
|
|
++(Item.I);
|
|
|
|
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
|
|
|
|
WL.push_back(ObjCMsgWLItem(Item.I, *NI));
|
|
|
|
}
|
2008-04-16 07:06:53 +08:00
|
|
|
|
2010-02-16 07:02:46 +08:00
|
|
|
// Now that the arguments are processed, handle the previsits checks.
|
|
|
|
ExplodedNodeSet DstPrevisit;
|
|
|
|
CheckerVisit(ME, DstPrevisit, ArgsEvaluated, true);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-02-16 07:02:46 +08:00
|
|
|
// Proceed with evaluate the message expression.
|
|
|
|
ExplodedNodeSet DstEval;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-02-16 07:02:46 +08:00
|
|
|
for (ExplodedNodeSet::iterator DI = DstPrevisit.begin(),
|
|
|
|
DE = DstPrevisit.end(); DI != DE; ++DI) {
|
2009-12-23 06:13:46 +08:00
|
|
|
|
2009-11-21 09:25:37 +08:00
|
|
|
Pred = *DI;
|
|
|
|
bool RaisesException = false;
|
2010-02-16 07:02:46 +08:00
|
|
|
unsigned OldSize = DstEval.size();
|
2009-12-23 06:13:46 +08:00
|
|
|
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
|
2010-02-16 07:02:46 +08:00
|
|
|
SaveOr OldHasGen(Builder->HasGeneratedNode);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Overhaul the AST representation of Objective-C message send
expressions, to improve source-location information, clarify the
actual receiver of the message, and pave the way for proper C++
support. The ObjCMessageExpr node represents four different kinds of
message sends in a single AST node:
1) Send to a object instance described by an expression (e.g., [x method:5])
2) Send to a class described by the class name (e.g., [NSString method:5])
3) Send to a superclass class (e.g, [super method:5] in class method)
4) Send to a superclass instance (e.g., [super method:5] in instance method)
Previously these four cases where tangled together. Now, they have
more distinct representations. Specific changes:
1) Unchanged; the object instance is represented by an Expr*.
2) Previously stored the ObjCInterfaceDecl* referring to the class
receiving the message. Now stores a TypeSourceInfo* so that we know
how the class was spelled. This both maintains typedef information
and opens the door for more complicated C++ types (e.g., dependent
types). There was an alternative, unused representation of these
sends by naming the class via an IdentifierInfo *. In practice, we
either had an ObjCInterfaceDecl *, from which we would get the
IdentifierInfo *, or we fell into the case below...
3) Previously represented by a class message whose IdentifierInfo *
referred to "super". Sema and CodeGen would use isStr("super") to
determine if they had a send to super. Now represented as a
"class super" send, where we have both the location of the "super"
keyword and the ObjCInterfaceDecl* of the superclass we're
targetting (statically).
4) Previously represented by an instance message whose receiver is a
an ObjCSuperExpr, which Sema and CodeGen would check for via
isa<ObjCSuperExpr>(). Now represented as an "instance super" send,
where we have both the location of the "super" keyword and the
ObjCInterfaceDecl* of the superclass we're targetting
(statically). Note that ObjCSuperExpr only has one remaining use in
the AST, which is for "super.prop" references.
The new representation of ObjCMessageExpr is 2 pointers smaller than
the old one, since it combines more storage. It also eliminates a leak
when we loaded message-send expressions from a precompiled header. The
representation also feels much cleaner to me; comments welcome!
This patch attempts to maintain the same semantics we previously had
with Objective-C message sends. In several places, there are massive
changes that boil down to simply replacing a nested-if structure such
as:
if (message has a receiver expression) {
// instance message
if (isa<ObjCSuperExpr>(...)) {
// send to super
} else {
// send to an object
}
} else {
// class message
if (name->isStr("super")) {
// class send to super
} else {
// send to class
}
}
with a switch
switch (E->getReceiverKind()) {
case ObjCMessageExpr::SuperInstance: ...
case ObjCMessageExpr::Instance: ...
case ObjCMessageExpr::SuperClass: ...
case ObjCMessageExpr::Class:...
}
There are quite a few places (particularly in the checkers) where
send-to-super is effectively ignored. I've placed FIXMEs in most of
them, and attempted to address send-to-super in a reasonable way. This
could use some review.
llvm-svn: 101972
2010-04-21 08:45:42 +08:00
|
|
|
if (const Expr *Receiver = ME->getInstanceReceiver()) {
|
2010-04-20 12:53:09 +08:00
|
|
|
const GRState *state = GetState(Pred);
|
2009-12-02 13:49:12 +08:00
|
|
|
|
|
|
|
// Bifurcate the state into nil and non-nil ones.
|
2010-02-16 07:02:46 +08:00
|
|
|
DefinedOrUnknownSVal receiverVal =
|
2010-02-09 00:18:51 +08:00
|
|
|
cast<DefinedOrUnknownSVal>(state->getSVal(Receiver));
|
2009-12-02 13:49:12 +08:00
|
|
|
|
|
|
|
const GRState *notNilState, *nilState;
|
|
|
|
llvm::tie(notNilState, nilState) = state->Assume(receiverVal);
|
|
|
|
|
2010-02-16 07:02:46 +08:00
|
|
|
// There are three cases: can be nil or non-nil, must be nil, must be
|
2009-12-02 13:49:12 +08:00
|
|
|
// non-nil. We handle must be nil, and merge the rest two into non-nil.
|
|
|
|
if (nilState && !notNilState) {
|
2010-02-16 07:02:46 +08:00
|
|
|
CheckerEvalNilReceiver(ME, DstEval, nilState, Pred);
|
2009-12-23 06:13:46 +08:00
|
|
|
continue;
|
2009-12-02 13:49:12 +08:00
|
|
|
}
|
|
|
|
|
2009-11-21 09:25:37 +08:00
|
|
|
// Check if the "raise" message was sent.
|
2010-02-16 07:02:46 +08:00
|
|
|
assert(notNilState);
|
2009-11-21 09:25:37 +08:00
|
|
|
if (ME->getSelector() == RaiseSel)
|
|
|
|
RaisesException = true;
|
2009-12-02 13:49:12 +08:00
|
|
|
|
|
|
|
// Check if we raise an exception. For now treat these as sinks.
|
|
|
|
// Eventually we will want to handle exceptions properly.
|
|
|
|
if (RaisesException)
|
|
|
|
Builder->BuildSinks = true;
|
|
|
|
|
|
|
|
// Dispatch to plug-in transfer function.
|
2010-02-16 07:02:46 +08:00
|
|
|
EvalObjCMessageExpr(DstEval, ME, Pred, notNilState);
|
2009-02-19 12:06:22 +08:00
|
|
|
}
|
Overhaul the AST representation of Objective-C message send
expressions, to improve source-location information, clarify the
actual receiver of the message, and pave the way for proper C++
support. The ObjCMessageExpr node represents four different kinds of
message sends in a single AST node:
1) Send to a object instance described by an expression (e.g., [x method:5])
2) Send to a class described by the class name (e.g., [NSString method:5])
3) Send to a superclass class (e.g, [super method:5] in class method)
4) Send to a superclass instance (e.g., [super method:5] in instance method)
Previously these four cases where tangled together. Now, they have
more distinct representations. Specific changes:
1) Unchanged; the object instance is represented by an Expr*.
2) Previously stored the ObjCInterfaceDecl* referring to the class
receiving the message. Now stores a TypeSourceInfo* so that we know
how the class was spelled. This both maintains typedef information
and opens the door for more complicated C++ types (e.g., dependent
types). There was an alternative, unused representation of these
sends by naming the class via an IdentifierInfo *. In practice, we
either had an ObjCInterfaceDecl *, from which we would get the
IdentifierInfo *, or we fell into the case below...
3) Previously represented by a class message whose IdentifierInfo *
referred to "super". Sema and CodeGen would use isStr("super") to
determine if they had a send to super. Now represented as a
"class super" send, where we have both the location of the "super"
keyword and the ObjCInterfaceDecl* of the superclass we're
targetting (statically).
4) Previously represented by an instance message whose receiver is a
an ObjCSuperExpr, which Sema and CodeGen would check for via
isa<ObjCSuperExpr>(). Now represented as an "instance super" send,
where we have both the location of the "super" keyword and the
ObjCInterfaceDecl* of the superclass we're targetting
(statically). Note that ObjCSuperExpr only has one remaining use in
the AST, which is for "super.prop" references.
The new representation of ObjCMessageExpr is 2 pointers smaller than
the old one, since it combines more storage. It also eliminates a leak
when we loaded message-send expressions from a precompiled header. The
representation also feels much cleaner to me; comments welcome!
This patch attempts to maintain the same semantics we previously had
with Objective-C message sends. In several places, there are massive
changes that boil down to simply replacing a nested-if structure such
as:
if (message has a receiver expression) {
// instance message
if (isa<ObjCSuperExpr>(...)) {
// send to super
} else {
// send to an object
}
} else {
// class message
if (name->isStr("super")) {
// class send to super
} else {
// send to class
}
}
with a switch
switch (E->getReceiverKind()) {
case ObjCMessageExpr::SuperInstance: ...
case ObjCMessageExpr::Instance: ...
case ObjCMessageExpr::SuperClass: ...
case ObjCMessageExpr::Class:...
}
There are quite a few places (particularly in the checkers) where
send-to-super is effectively ignored. I've placed FIXMEs in most of
them, and attempted to address send-to-super in a reasonable way. This
could use some review.
llvm-svn: 101972
2010-04-21 08:45:42 +08:00
|
|
|
else if (ObjCInterfaceDecl *Iface = ME->getReceiverInterface()) {
|
|
|
|
IdentifierInfo* ClsName = Iface->getIdentifier();
|
2009-11-21 09:25:37 +08:00
|
|
|
Selector S = ME->getSelector();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-21 09:25:37 +08:00
|
|
|
// Check for special instance methods.
|
|
|
|
if (!NSExceptionII) {
|
|
|
|
ASTContext& Ctx = getContext();
|
|
|
|
NSExceptionII = &Ctx.Idents.get("NSException");
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-21 09:25:37 +08:00
|
|
|
if (ClsName == NSExceptionII) {
|
|
|
|
enum { NUM_RAISE_SELECTORS = 2 };
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-21 09:25:37 +08:00
|
|
|
// Lazily create a cache of the selectors.
|
|
|
|
if (!NSExceptionInstanceRaiseSelectors) {
|
|
|
|
ASTContext& Ctx = getContext();
|
2010-02-16 07:02:46 +08:00
|
|
|
NSExceptionInstanceRaiseSelectors =
|
|
|
|
new Selector[NUM_RAISE_SELECTORS];
|
2009-11-21 09:25:37 +08:00
|
|
|
llvm::SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
|
|
|
|
unsigned idx = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-21 09:25:37 +08:00
|
|
|
// raise:format:
|
|
|
|
II.push_back(&Ctx.Idents.get("raise"));
|
|
|
|
II.push_back(&Ctx.Idents.get("format"));
|
|
|
|
NSExceptionInstanceRaiseSelectors[idx++] =
|
|
|
|
Ctx.Selectors.getSelector(II.size(), &II[0]);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-21 09:25:37 +08:00
|
|
|
// raise:format::arguments:
|
|
|
|
II.push_back(&Ctx.Idents.get("arguments"));
|
|
|
|
NSExceptionInstanceRaiseSelectors[idx++] =
|
|
|
|
Ctx.Selectors.getSelector(II.size(), &II[0]);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-21 09:25:37 +08:00
|
|
|
for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i)
|
|
|
|
if (S == NSExceptionInstanceRaiseSelectors[i]) {
|
2009-12-23 06:13:46 +08:00
|
|
|
RaisesException = true;
|
|
|
|
break;
|
2009-11-21 09:25:37 +08:00
|
|
|
}
|
2008-05-02 02:33:28 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-12-02 13:49:12 +08:00
|
|
|
// Check if we raise an exception. For now treat these as sinks.
|
|
|
|
// Eventually we will want to handle exceptions properly.
|
|
|
|
if (RaisesException)
|
|
|
|
Builder->BuildSinks = true;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-12-02 13:49:12 +08:00
|
|
|
// Dispatch to plug-in transfer function.
|
2010-02-16 07:02:46 +08:00
|
|
|
EvalObjCMessageExpr(DstEval, ME, Pred, Builder->GetState(Pred));
|
2009-12-02 13:49:12 +08:00
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-23 06:13:46 +08:00
|
|
|
// Handle the case where no nodes where generated. Auto-generate that
|
|
|
|
// contains the updated state if we aren't generating sinks.
|
2010-02-16 07:02:46 +08:00
|
|
|
if (!Builder->BuildSinks && DstEval.size() == OldSize &&
|
2009-12-23 06:13:46 +08:00
|
|
|
!Builder->HasGeneratedNode)
|
2010-02-16 07:02:46 +08:00
|
|
|
MakeNode(DstEval, ME, Pred, GetState(Pred));
|
2009-11-21 09:25:37 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-12-23 06:13:46 +08:00
|
|
|
// Finally, perform the post-condition check of the ObjCMessageExpr and store
|
|
|
|
// the created nodes in 'Dst'.
|
|
|
|
if (!(!asLValue && ReceiverReturnsReference(ME))) {
|
2010-02-16 07:02:46 +08:00
|
|
|
CheckerVisit(ME, Dst, DstEval, false);
|
2009-12-23 06:13:46 +08:00
|
|
|
return;
|
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-23 06:13:46 +08:00
|
|
|
// Handle the case where the message expression returns a reference but
|
|
|
|
// we expect an rvalue. For such cases, convert the reference to
|
2010-02-16 07:02:46 +08:00
|
|
|
// an rvalue.
|
2009-12-23 06:13:46 +08:00
|
|
|
// FIXME: This conversion doesn't actually happen unless the result
|
|
|
|
// of ObjCMessageExpr is consumed by another expression.
|
|
|
|
ExplodedNodeSet DstRValueConvert;
|
2010-02-16 07:02:46 +08:00
|
|
|
CheckerVisit(ME, DstRValueConvert, DstEval, false);
|
2009-12-23 06:13:46 +08:00
|
|
|
QualType LoadTy = ME->getType();
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-23 06:13:46 +08:00
|
|
|
static int *ConvertToRvalueTag = 0;
|
|
|
|
for (ExplodedNodeSet::iterator NI = DstRValueConvert.begin(),
|
2010-02-16 07:02:46 +08:00
|
|
|
NE = DstRValueConvert.end(); NI != NE; ++NI) {
|
2009-12-23 06:13:46 +08:00
|
|
|
const GRState *state = GetState(*NI);
|
2010-02-09 00:18:51 +08:00
|
|
|
EvalLoad(Dst, ME, *NI, state, state->getSVal(ME),
|
2009-12-23 06:13:46 +08:00
|
|
|
&ConvertToRvalueTag, LoadTy);
|
|
|
|
}
|
2008-02-19 09:44:53 +08:00
|
|
|
}
|
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Transfer functions: Miscellaneous statements.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
|
|
|
|
ExplodedNode *Pred, ExplodedNodeSet &Dst,
|
|
|
|
bool asLValue) {
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet S1;
|
2008-02-20 02:52:54 +08:00
|
|
|
QualType T = CastE->getType();
|
2008-10-21 14:54:23 +08:00
|
|
|
QualType ExTy = Ex->getType();
|
2008-10-22 16:02:16 +08:00
|
|
|
|
2008-10-31 15:26:14 +08:00
|
|
|
if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE))
|
2008-10-28 03:41:14 +08:00
|
|
|
T = ExCast->getTypeAsWritten();
|
|
|
|
|
2009-12-23 08:26:16 +08:00
|
|
|
if (ExTy->isArrayType() || ExTy->isFunctionType() || T->isReferenceType() ||
|
|
|
|
asLValue)
|
2008-10-16 14:09:51 +08:00
|
|
|
VisitLValue(Ex, Pred, S1);
|
2008-03-05 06:16:08 +08:00
|
|
|
else
|
|
|
|
Visit(Ex, Pred, S1);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-09 16:07:38 +08:00
|
|
|
ExplodedNodeSet S2;
|
|
|
|
CheckerVisit(CastE, S2, S1, true);
|
|
|
|
|
2009-12-23 08:26:16 +08:00
|
|
|
// If we are evaluating the cast in an lvalue context, we implicitly want
|
|
|
|
// the cast to evaluate to a location.
|
|
|
|
if (asLValue) {
|
|
|
|
ASTContext &Ctx = getContext();
|
|
|
|
T = Ctx.getPointerType(Ctx.getCanonicalType(T));
|
2009-12-23 09:19:20 +08:00
|
|
|
ExTy = Ctx.getPointerType(Ctx.getCanonicalType(ExTy));
|
2009-12-23 08:26:16 +08:00
|
|
|
}
|
2009-07-22 05:03:30 +08:00
|
|
|
|
2010-01-22 12:30:00 +08:00
|
|
|
switch (CastE->getCastKind()) {
|
|
|
|
case CastExpr::CK_ToVoid:
|
|
|
|
assert(!asLValue);
|
|
|
|
for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I)
|
|
|
|
Dst.Add(*I);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case CastExpr::CK_NoOp:
|
|
|
|
case CastExpr::CK_FunctionToPointerDecay:
|
|
|
|
for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
|
|
|
|
// Copy the SVal of Ex to CastE.
|
|
|
|
ExplodedNode *N = *I;
|
|
|
|
const GRState *state = GetState(N);
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal V = state->getSVal(Ex);
|
2010-01-22 12:30:00 +08:00
|
|
|
state = state->BindExpr(CastE, V);
|
|
|
|
MakeNode(Dst, CastE, N, state);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
case CastExpr::CK_Unknown:
|
|
|
|
case CastExpr::CK_ArrayToPointerDecay:
|
|
|
|
case CastExpr::CK_BitCast:
|
2010-07-14 07:17:26 +08:00
|
|
|
case CastExpr::CK_LValueBitCast:
|
2010-01-22 12:30:00 +08:00
|
|
|
case CastExpr::CK_IntegralCast:
|
|
|
|
case CastExpr::CK_IntegralToPointer:
|
|
|
|
case CastExpr::CK_PointerToIntegral:
|
|
|
|
case CastExpr::CK_IntegralToFloating:
|
|
|
|
case CastExpr::CK_FloatingToIntegral:
|
|
|
|
case CastExpr::CK_FloatingCast:
|
|
|
|
case CastExpr::CK_AnyPointerToObjCPointerCast:
|
|
|
|
case CastExpr::CK_AnyPointerToBlockPointerCast:
|
|
|
|
case CastExpr::CK_DerivedToBase:
|
2010-06-23 03:05:10 +08:00
|
|
|
case CastExpr::CK_UncheckedDerivedToBase: {
|
2010-01-22 12:30:00 +08:00
|
|
|
// Delegate to SValuator to process.
|
|
|
|
for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
|
|
|
|
ExplodedNode* N = *I;
|
|
|
|
const GRState* state = GetState(N);
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal V = state->getSVal(Ex);
|
2010-02-04 12:56:43 +08:00
|
|
|
V = SVator.EvalCast(V, T, ExTy);
|
|
|
|
state = state->BindExpr(CastE, V);
|
2010-01-22 12:30:00 +08:00
|
|
|
MakeNode(Dst, CastE, N, state);
|
|
|
|
}
|
|
|
|
return;
|
2010-06-23 03:05:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Various C++ casts that are not handled yet.
|
|
|
|
case CastExpr::CK_Dynamic:
|
|
|
|
case CastExpr::CK_ToUnion:
|
|
|
|
case CastExpr::CK_BaseToDerived:
|
|
|
|
case CastExpr::CK_NullToMemberPointer:
|
|
|
|
case CastExpr::CK_BaseToDerivedMemberPointer:
|
|
|
|
case CastExpr::CK_DerivedToBaseMemberPointer:
|
|
|
|
case CastExpr::CK_UserDefinedConversion:
|
|
|
|
case CastExpr::CK_ConstructorConversion:
|
|
|
|
case CastExpr::CK_VectorSplat:
|
|
|
|
case CastExpr::CK_MemberPointerToBoolean: {
|
|
|
|
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
|
|
|
|
Builder->BuildSinks = true;
|
|
|
|
MakeNode(Dst, CastE, Pred, GetState(Pred));
|
|
|
|
return;
|
|
|
|
}
|
2008-01-24 10:02:54 +08:00
|
|
|
}
|
2008-01-25 04:55:43 +08:00
|
|
|
}
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr* CL,
|
2009-09-09 23:08:12 +08:00
|
|
|
ExplodedNode* Pred,
|
|
|
|
ExplodedNodeSet& Dst,
|
2008-11-07 18:38:33 +08:00
|
|
|
bool asLValue) {
|
2010-07-20 14:22:24 +08:00
|
|
|
const InitListExpr* ILE
|
|
|
|
= cast<InitListExpr>(CL->getInitializer()->IgnoreParens());
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
2008-10-28 05:54:31 +08:00
|
|
|
Visit(ILE, Pred, Tmp);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
for (ExplodedNodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I!=EI; ++I) {
|
2009-02-13 09:45:31 +08:00
|
|
|
const GRState* state = GetState(*I);
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal ILV = state->getSVal(ILE);
|
2009-12-08 06:05:27 +08:00
|
|
|
const LocationContext *LC = (*I)->getLocationContext();
|
|
|
|
state = state->bindCompoundLiteral(CL, LC, ILV);
|
2008-10-28 05:54:31 +08:00
|
|
|
|
2009-12-08 06:05:27 +08:00
|
|
|
if (asLValue) {
|
|
|
|
MakeNode(Dst, CL, *I, state->BindExpr(CL, state->getLValue(CL, LC)));
|
|
|
|
}
|
2008-11-07 18:38:33 +08:00
|
|
|
else
|
2009-08-28 06:17:37 +08:00
|
|
|
MakeNode(Dst, CL, *I, state->BindExpr(CL, ILV));
|
2008-10-28 05:54:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
|
2009-09-09 23:08:12 +08:00
|
|
|
ExplodedNodeSet& Dst) {
|
2008-04-23 06:25:27 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
// The CFG has one DeclStmt per Decl.
|
2010-07-20 14:22:24 +08:00
|
|
|
const Decl* D = *DS->decl_begin();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-29 02:34:26 +08:00
|
|
|
if (!D || !isa<VarDecl>(D))
|
2008-04-23 06:25:27 +08:00
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
const VarDecl* VD = dyn_cast<VarDecl>(D);
|
2010-07-20 14:22:24 +08:00
|
|
|
const Expr* InitEx = const_cast<Expr*>(VD->getInit());
|
2008-04-23 06:25:27 +08:00
|
|
|
|
|
|
|
// FIXME: static variables may have an initializer, but the second
|
|
|
|
// time a function is called those values may not be current.
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
2008-04-23 06:25:27 +08:00
|
|
|
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
if (InitEx) {
|
2010-04-01 11:47:27 +08:00
|
|
|
QualType InitTy = InitEx->getType();
|
|
|
|
if (getContext().getLangOptions().CPlusPlus && InitTy->isRecordType()) {
|
|
|
|
// Delegate expressions of C++ record type evaluation to AggExprVisitor.
|
|
|
|
VisitAggExpr(InitEx, GetState(Pred)->getLValue(VD,
|
2010-03-16 21:14:16 +08:00
|
|
|
Pred->getLocationContext()), Pred, Dst);
|
|
|
|
return;
|
|
|
|
} else if (VD->getType()->isReferenceType())
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
VisitLValue(InitEx, Pred, Tmp);
|
|
|
|
else
|
|
|
|
Visit(InitEx, Pred, Tmp);
|
|
|
|
}
|
2009-07-18 07:48:26 +08:00
|
|
|
else
|
2008-08-29 02:34:26 +08:00
|
|
|
Tmp.Add(Pred);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-07 11:56:57 +08:00
|
|
|
ExplodedNodeSet Tmp2;
|
|
|
|
CheckerVisit(DS, Tmp2, Tmp, true);
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-07 11:56:57 +08:00
|
|
|
for (ExplodedNodeSet::iterator I=Tmp2.begin(), E=Tmp2.end(); I!=E; ++I) {
|
2009-11-03 20:13:38 +08:00
|
|
|
ExplodedNode *N = *I;
|
2009-11-07 11:56:57 +08:00
|
|
|
const GRState *state = GetState(N);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-14 09:54:57 +08:00
|
|
|
// Decls without InitExpr are not initialized explicitly.
|
2009-11-03 20:13:38 +08:00
|
|
|
const LocationContext *LC = N->getLocationContext();
|
2009-08-22 06:28:32 +08:00
|
|
|
|
2009-02-14 09:54:57 +08:00
|
|
|
if (InitEx) {
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal InitVal = state->getSVal(InitEx);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-14 09:54:57 +08:00
|
|
|
// Recover some path-sensitivity if a scalar value evaluated to
|
|
|
|
// UnknownVal.
|
2010-03-03 05:43:52 +08:00
|
|
|
if ((InitVal.isUnknown() ||
|
|
|
|
!getConstraintManager().canReasonAbout(InitVal)) &&
|
|
|
|
!VD->getType()->isReferenceType()) {
|
2010-02-16 07:02:46 +08:00
|
|
|
InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx,
|
2009-11-03 20:13:38 +08:00
|
|
|
Builder->getCurrentBlockCount());
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-05 08:42:23 +08:00
|
|
|
EvalBind(Dst, DS, DS, *I, state,
|
2010-02-16 07:02:46 +08:00
|
|
|
loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true);
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2009-02-14 09:54:57 +08:00
|
|
|
else {
|
2009-11-04 08:09:15 +08:00
|
|
|
state = state->bindDeclWithNoInit(state->getRegion(VD, LC));
|
2009-02-14 09:54:57 +08:00
|
|
|
MakeNode(Dst, DS, *I, state);
|
|
|
|
}
|
2008-04-23 06:25:27 +08:00
|
|
|
}
|
|
|
|
}
|
2008-02-05 08:26:40 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitCondInit(const VarDecl *VD, const Stmt *S,
|
2009-12-24 08:40:03 +08:00
|
|
|
ExplodedNode *Pred, ExplodedNodeSet& Dst) {
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
const Expr* InitEx = VD->getInit();
|
2009-12-23 12:49:01 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
|
|
|
Visit(InitEx, Pred, Tmp);
|
|
|
|
|
|
|
|
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
|
|
|
|
ExplodedNode *N = *I;
|
|
|
|
const GRState *state = GetState(N);
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-23 12:49:01 +08:00
|
|
|
const LocationContext *LC = N->getLocationContext();
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal InitVal = state->getSVal(InitEx);
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-23 12:49:01 +08:00
|
|
|
// Recover some path-sensitivity if a scalar value evaluated to
|
|
|
|
// UnknownVal.
|
|
|
|
if (InitVal.isUnknown() ||
|
|
|
|
!getConstraintManager().canReasonAbout(InitVal)) {
|
2010-02-16 07:02:46 +08:00
|
|
|
InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx,
|
2009-12-23 12:49:01 +08:00
|
|
|
Builder->getCurrentBlockCount());
|
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-12-24 08:40:03 +08:00
|
|
|
EvalBind(Dst, S, S, N, state,
|
2009-12-23 12:49:01 +08:00
|
|
|
loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-31 01:47:32 +08:00
|
|
|
namespace {
|
|
|
|
// This class is used by VisitInitListExpr as an item in a worklist
|
|
|
|
// for processing the values contained in an InitListExpr.
|
2009-11-28 14:07:30 +08:00
|
|
|
class InitListWLItem {
|
2008-10-31 01:47:32 +08:00
|
|
|
public:
|
|
|
|
llvm::ImmutableList<SVal> Vals;
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNode* N;
|
2010-07-20 14:22:24 +08:00
|
|
|
InitListExpr::const_reverse_iterator Itr;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
InitListWLItem(ExplodedNode* n, llvm::ImmutableList<SVal> vals,
|
2010-07-20 14:22:24 +08:00
|
|
|
InitListExpr::const_reverse_iterator itr)
|
2008-10-31 01:47:32 +08:00
|
|
|
: Vals(vals), N(n), Itr(itr) {}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitInitListExpr(const InitListExpr* E, ExplodedNode* Pred,
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet& Dst) {
|
2008-10-30 13:02:23 +08:00
|
|
|
|
2008-10-31 07:14:36 +08:00
|
|
|
const GRState* state = GetState(Pred);
|
2008-11-13 13:05:34 +08:00
|
|
|
QualType T = getContext().getCanonicalType(E->getType());
|
2009-09-09 23:08:12 +08:00
|
|
|
unsigned NumInitElements = E->getNumInits();
|
2008-10-30 13:02:23 +08:00
|
|
|
|
2010-04-27 05:31:17 +08:00
|
|
|
if (T->isArrayType() || T->isRecordType() || T->isVectorType()) {
|
2008-10-31 07:14:36 +08:00
|
|
|
llvm::ImmutableList<SVal> StartVals = getBasicVals().getEmptySValList();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-31 07:14:36 +08:00
|
|
|
// Handle base case where the initializer has no elements.
|
|
|
|
// e.g: static int* myArray[] = {};
|
|
|
|
if (NumInitElements == 0) {
|
2009-06-23 17:02:15 +08:00
|
|
|
SVal V = ValMgr.makeCompoundVal(T, StartVals);
|
2009-08-28 06:17:37 +08:00
|
|
|
MakeNode(Dst, E, Pred, state->BindExpr(E, V));
|
2008-10-31 07:14:36 +08:00
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
|
|
|
|
2008-10-31 07:14:36 +08:00
|
|
|
// Create a worklist to process the initializers.
|
|
|
|
llvm::SmallVector<InitListWLItem, 10> WorkList;
|
2009-09-09 23:08:12 +08:00
|
|
|
WorkList.reserve(NumInitElements);
|
|
|
|
WorkList.push_back(InitListWLItem(Pred, StartVals, E->rbegin()));
|
2010-07-20 14:22:24 +08:00
|
|
|
InitListExpr::const_reverse_iterator ItrEnd = E->rend();
|
2009-09-23 05:19:14 +08:00
|
|
|
assert(!(E->rbegin() == E->rend()));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-31 07:14:36 +08:00
|
|
|
// Process the worklist until it is empty.
|
2008-10-31 01:47:32 +08:00
|
|
|
while (!WorkList.empty()) {
|
|
|
|
InitListWLItem X = WorkList.back();
|
|
|
|
WorkList.pop_back();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
2008-10-31 01:47:32 +08:00
|
|
|
Visit(*X.Itr, X.N, Tmp);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
InitListExpr::const_reverse_iterator NewItr = X.Itr + 1;
|
2008-10-30 13:02:23 +08:00
|
|
|
|
2009-12-16 19:27:52 +08:00
|
|
|
for (ExplodedNodeSet::iterator NI=Tmp.begin(),NE=Tmp.end();NI!=NE;++NI) {
|
2008-10-31 01:47:32 +08:00
|
|
|
// Get the last initializer value.
|
|
|
|
state = GetState(*NI);
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal InitV = state->getSVal(cast<Expr>(*X.Itr));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-31 01:47:32 +08:00
|
|
|
// Construct the new list of values by prepending the new value to
|
|
|
|
// the already constructed list.
|
|
|
|
llvm::ImmutableList<SVal> NewVals =
|
|
|
|
getBasicVals().consVals(InitV, X.Vals);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-31 01:47:32 +08:00
|
|
|
if (NewItr == ItrEnd) {
|
2008-10-31 11:01:26 +08:00
|
|
|
// Now we have a list holding all init values. Make CompoundValData.
|
2009-06-23 17:02:15 +08:00
|
|
|
SVal V = ValMgr.makeCompoundVal(T, NewVals);
|
2008-10-30 13:02:23 +08:00
|
|
|
|
2008-10-31 01:47:32 +08:00
|
|
|
// Make final state and node.
|
2009-08-28 06:17:37 +08:00
|
|
|
MakeNode(Dst, E, *NI, state->BindExpr(E, V));
|
2008-10-31 01:47:32 +08:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Still some initializer values to go. Push them onto the worklist.
|
|
|
|
WorkList.push_back(InitListWLItem(*NI, NewVals, NewItr));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-31 02:34:31 +08:00
|
|
|
return;
|
2008-10-30 13:02:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Loc::IsLocType(T) || T->isIntegerType()) {
|
|
|
|
assert (E->getNumInits() == 1);
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
2010-07-20 14:22:24 +08:00
|
|
|
const Expr* Init = E->getInit(0);
|
2008-10-30 13:02:23 +08:00
|
|
|
Visit(Init, Pred, Tmp);
|
2009-12-16 19:27:52 +08:00
|
|
|
for (ExplodedNodeSet::iterator I=Tmp.begin(), EI=Tmp.end(); I != EI; ++I) {
|
2008-10-30 13:02:23 +08:00
|
|
|
state = GetState(*I);
|
2010-02-09 00:18:51 +08:00
|
|
|
MakeNode(Dst, E, *I, state->BindExpr(E, state->getSVal(Init)));
|
2008-10-30 13:02:23 +08:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(0 && "unprocessed InitListExpr type");
|
|
|
|
}
|
2008-02-05 08:26:40 +08:00
|
|
|
|
2008-11-12 01:56:53 +08:00
|
|
|
/// VisitSizeOfAlignOfExpr - Transfer function for sizeof(type).
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr* Ex,
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNode* Pred,
|
|
|
|
ExplodedNodeSet& Dst) {
|
2008-11-12 01:56:53 +08:00
|
|
|
QualType T = Ex->getTypeOfArgument();
|
2010-01-12 01:06:35 +08:00
|
|
|
CharUnits amt;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-15 11:13:20 +08:00
|
|
|
if (Ex->isSizeOf()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
if (T == getContext().VoidTy) {
|
2008-12-16 02:51:00 +08:00
|
|
|
// sizeof(void) == 1 byte.
|
2010-01-12 01:06:35 +08:00
|
|
|
amt = CharUnits::One();
|
2008-12-16 02:51:00 +08:00
|
|
|
}
|
2010-07-05 12:42:43 +08:00
|
|
|
else if (!T->isConstantSizeType()) {
|
|
|
|
assert(T->isVariableArrayType() && "Unknown non-constant-sized type.");
|
|
|
|
|
|
|
|
// FIXME: Add support for VLA type arguments, not just VLA expressions.
|
|
|
|
// When that happens, we should probably refactor VLASizeChecker's code.
|
|
|
|
if (Ex->isArgumentType()) {
|
|
|
|
Dst.Add(Pred);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the size by getting the extent of the sub-expression.
|
|
|
|
// First, visit the sub-expression to find its region.
|
2010-07-20 14:22:24 +08:00
|
|
|
const Expr *Arg = Ex->getArgumentExpr();
|
2010-07-05 12:42:43 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
|
|
|
VisitLValue(Arg, Pred, Tmp);
|
|
|
|
|
|
|
|
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
|
|
|
|
const GRState* state = GetState(*I);
|
|
|
|
const MemRegion *MR = state->getSVal(Arg).getAsRegion();
|
|
|
|
|
|
|
|
// If the subexpression can't be resolved to a region, we don't know
|
|
|
|
// anything about its size. Just leave the state as is and continue.
|
|
|
|
if (!MR) {
|
|
|
|
Dst.Add(*I);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The result is the extent of the VLA.
|
|
|
|
SVal Extent = cast<SubRegion>(MR)->getExtent(ValMgr);
|
|
|
|
MakeNode(Dst, Ex, *I, state->BindExpr(Ex, Extent));
|
|
|
|
}
|
|
|
|
|
2008-03-15 11:13:20 +08:00
|
|
|
return;
|
2008-12-16 02:51:00 +08:00
|
|
|
}
|
2010-05-15 19:32:37 +08:00
|
|
|
else if (T->getAs<ObjCObjectType>()) {
|
|
|
|
// Some code tries to take the sizeof an ObjCObjectType, relying that
|
2008-12-16 02:51:00 +08:00
|
|
|
// the compiler has laid out its representation. Just report Unknown
|
2009-09-09 23:08:12 +08:00
|
|
|
// for these.
|
2010-02-02 10:01:51 +08:00
|
|
|
Dst.Add(Pred);
|
2008-05-01 05:31:12 +08:00
|
|
|
return;
|
2008-12-16 02:51:00 +08:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// All other cases.
|
2010-01-12 01:06:35 +08:00
|
|
|
amt = getContext().getTypeSizeInChars(T);
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2008-03-15 11:13:20 +08:00
|
|
|
}
|
|
|
|
else // Get alignment of the type.
|
2010-01-27 20:54:25 +08:00
|
|
|
amt = getContext().getTypeAlignInChars(T);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-22 05:30:14 +08:00
|
|
|
MakeNode(Dst, Ex, Pred,
|
2010-02-16 07:02:46 +08:00
|
|
|
GetState(Pred)->BindExpr(Ex,
|
2010-01-12 01:06:35 +08:00
|
|
|
ValMgr.makeIntVal(amt.getQuantity(), Ex->getType())));
|
2008-04-22 07:43:38 +08:00
|
|
|
}
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitOffsetOfExpr(const OffsetOfExpr* OOE,
|
|
|
|
ExplodedNode* Pred, ExplodedNodeSet& Dst) {
|
Completely reimplement __builtin_offsetof, based on a patch by Roberto
Amadini.
This change introduces a new expression node type, OffsetOfExpr, that
describes __builtin_offsetof. Previously, __builtin_offsetof was
implemented using a unary operator whose subexpression involved
various synthesized array-subscript and member-reference expressions,
which was ugly and made it very hard to instantiate as a
template. OffsetOfExpr represents the AST more faithfully, with proper
type source information and a more compact representation.
OffsetOfExpr also has support for dependent __builtin_offsetof
expressions; it can be value-dependent, but will never be
type-dependent (like sizeof or alignof). This commit introduces
template instantiation for __builtin_offsetof as well.
There are two major caveats to this patch:
1) CodeGen cannot handle the case where __builtin_offsetof is not a
constant expression, so it produces an error. So, to avoid
regressing in C, we retain the old UnaryOperator-based
__builtin_offsetof implementation in C while using the shiny new
OffsetOfExpr implementation in C++. The old implementation can go
away once we have proper CodeGen support for this case, which we
expect won't cause much trouble in C++.
2) __builtin_offsetof doesn't work well with non-POD class types,
particularly when the designated field is found within a base
class. I will address this in a subsequent patch.
Fixes PR5880 and a bunch of assertions when building Boost.Python
tests.
llvm-svn: 102542
2010-04-29 06:16:22 +08:00
|
|
|
Expr::EvalResult Res;
|
|
|
|
if (OOE->Evaluate(Res, getContext()) && Res.Val.isInt()) {
|
|
|
|
const APSInt &IV = Res.Val.getInt();
|
|
|
|
assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType()));
|
|
|
|
assert(OOE->getType()->isIntegerType());
|
|
|
|
assert(IV.isSigned() == OOE->getType()->isSignedIntegerType());
|
|
|
|
SVal X = ValMgr.makeIntVal(IV);
|
|
|
|
MakeNode(Dst, OOE, Pred, GetState(Pred)->BindExpr(OOE, X));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// FIXME: Handle the case where __builtin_offsetof is not a constant.
|
|
|
|
Dst.Add(Pred);
|
|
|
|
}
|
2008-02-20 12:02:35 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitUnaryOperator(const UnaryOperator* U,
|
|
|
|
ExplodedNode* Pred,
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet& Dst, bool asLValue) {
|
2008-04-30 05:04:26 +08:00
|
|
|
|
2008-02-20 12:02:35 +08:00
|
|
|
switch (U->getOpcode()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-20 12:02:35 +08:00
|
|
|
default:
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
case UnaryOperator::Deref: {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
const Expr* Ex = U->getSubExpr()->IgnoreParens();
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
2008-04-30 05:04:26 +08:00
|
|
|
Visit(Ex, Pred, Tmp);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-13 09:45:31 +08:00
|
|
|
const GRState* state = GetState(*I);
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal location = state->getSVal(Ex);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-16 14:09:51 +08:00
|
|
|
if (asLValue)
|
2009-08-28 06:17:37 +08:00
|
|
|
MakeNode(Dst, U, *I, state->BindExpr(U, location),
|
2009-05-08 02:27:16 +08:00
|
|
|
ProgramPoint::PostLValueKind);
|
2008-04-30 05:04:26 +08:00
|
|
|
else
|
2009-02-13 09:45:31 +08:00
|
|
|
EvalLoad(Dst, U, *I, state, location);
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2008-02-22 02:02:17 +08:00
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
return;
|
2008-02-22 02:02:17 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-06-20 01:55:38 +08:00
|
|
|
case UnaryOperator::Real: {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
const Expr* Ex = U->getSubExpr()->IgnoreParens();
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
2008-06-20 01:55:38 +08:00
|
|
|
Visit(Ex, Pred, Tmp);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-17 13:57:07 +08:00
|
|
|
// FIXME: We don't have complex SValues yet.
|
2008-06-20 01:55:38 +08:00
|
|
|
if (Ex->getType()->isAnyComplexType()) {
|
|
|
|
// Just report "Unknown."
|
|
|
|
Dst.Add(*I);
|
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-06-20 01:55:38 +08:00
|
|
|
// For all other types, UnaryOperator::Real is an identity operation.
|
|
|
|
assert (U->getType() == Ex->getType());
|
2009-02-13 09:45:31 +08:00
|
|
|
const GRState* state = GetState(*I);
|
2010-02-09 00:18:51 +08:00
|
|
|
MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex)));
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
|
|
|
|
2008-06-20 01:55:38 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-06-20 01:55:38 +08:00
|
|
|
case UnaryOperator::Imag: {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
const Expr* Ex = U->getSubExpr()->IgnoreParens();
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
2008-06-20 01:55:38 +08:00
|
|
|
Visit(Ex, Pred, Tmp);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
|
2008-10-17 13:57:07 +08:00
|
|
|
// FIXME: We don't have complex SValues yet.
|
2008-06-20 01:55:38 +08:00
|
|
|
if (Ex->getType()->isAnyComplexType()) {
|
|
|
|
// Just report "Unknown."
|
|
|
|
Dst.Add(*I);
|
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-17 09:28:55 +08:00
|
|
|
// For all other types, UnaryOperator::Imag returns 0.
|
2009-02-13 09:45:31 +08:00
|
|
|
const GRState* state = GetState(*I);
|
2009-06-23 17:02:15 +08:00
|
|
|
SVal X = ValMgr.makeZeroVal(Ex->getType());
|
2009-08-28 06:17:37 +08:00
|
|
|
MakeNode(Dst, U, *I, state->BindExpr(U, X));
|
2008-06-20 01:55:38 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-06-20 01:55:38 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-15 08:40:32 +08:00
|
|
|
case UnaryOperator::OffsetOf: {
|
2009-09-15 12:19:09 +08:00
|
|
|
Expr::EvalResult Res;
|
|
|
|
if (U->Evaluate(Res, getContext()) && Res.Val.isInt()) {
|
Completely reimplement __builtin_offsetof, based on a patch by Roberto
Amadini.
This change introduces a new expression node type, OffsetOfExpr, that
describes __builtin_offsetof. Previously, __builtin_offsetof was
implemented using a unary operator whose subexpression involved
various synthesized array-subscript and member-reference expressions,
which was ugly and made it very hard to instantiate as a
template. OffsetOfExpr represents the AST more faithfully, with proper
type source information and a more compact representation.
OffsetOfExpr also has support for dependent __builtin_offsetof
expressions; it can be value-dependent, but will never be
type-dependent (like sizeof or alignof). This commit introduces
template instantiation for __builtin_offsetof as well.
There are two major caveats to this patch:
1) CodeGen cannot handle the case where __builtin_offsetof is not a
constant expression, so it produces an error. So, to avoid
regressing in C, we retain the old UnaryOperator-based
__builtin_offsetof implementation in C while using the shiny new
OffsetOfExpr implementation in C++. The old implementation can go
away once we have proper CodeGen support for this case, which we
expect won't cause much trouble in C++.
2) __builtin_offsetof doesn't work well with non-POD class types,
particularly when the designated field is found within a base
class. I will address this in a subsequent patch.
Fixes PR5880 and a bunch of assertions when building Boost.Python
tests.
llvm-svn: 102542
2010-04-29 06:16:22 +08:00
|
|
|
const APSInt &IV = Res.Val.getInt();
|
|
|
|
assert(IV.getBitWidth() == getContext().getTypeSize(U->getType()));
|
|
|
|
assert(U->getType()->isIntegerType());
|
|
|
|
assert(IV.isSigned() == U->getType()->isSignedIntegerType());
|
|
|
|
SVal X = ValMgr.makeIntVal(IV);
|
|
|
|
MakeNode(Dst, U, Pred, GetState(Pred)->BindExpr(U, X));
|
|
|
|
return;
|
|
|
|
}
|
2009-09-15 12:19:09 +08:00
|
|
|
// FIXME: Handle the case where __builtin_offsetof is not a constant.
|
|
|
|
Dst.Add(Pred);
|
2008-05-01 05:45:55 +08:00
|
|
|
return;
|
2009-09-15 08:40:32 +08:00
|
|
|
}
|
Completely reimplement __builtin_offsetof, based on a patch by Roberto
Amadini.
This change introduces a new expression node type, OffsetOfExpr, that
describes __builtin_offsetof. Previously, __builtin_offsetof was
implemented using a unary operator whose subexpression involved
various synthesized array-subscript and member-reference expressions,
which was ugly and made it very hard to instantiate as a
template. OffsetOfExpr represents the AST more faithfully, with proper
type source information and a more compact representation.
OffsetOfExpr also has support for dependent __builtin_offsetof
expressions; it can be value-dependent, but will never be
type-dependent (like sizeof or alignof). This commit introduces
template instantiation for __builtin_offsetof as well.
There are two major caveats to this patch:
1) CodeGen cannot handle the case where __builtin_offsetof is not a
constant expression, so it produces an error. So, to avoid
regressing in C, we retain the old UnaryOperator-based
__builtin_offsetof implementation in C while using the shiny new
OffsetOfExpr implementation in C++. The old implementation can go
away once we have proper CodeGen support for this case, which we
expect won't cause much trouble in C++.
2) __builtin_offsetof doesn't work well with non-POD class types,
particularly when the designated field is found within a base
class. I will address this in a subsequent patch.
Fixes PR5880 and a bunch of assertions when building Boost.Python
tests.
llvm-svn: 102542
2010-04-29 06:16:22 +08:00
|
|
|
|
2010-06-27 06:40:52 +08:00
|
|
|
case UnaryOperator::Plus: assert(!asLValue); // FALL-THROUGH.
|
2008-04-30 05:04:26 +08:00
|
|
|
case UnaryOperator::Extension: {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
// Unary "+" is a no-op, similar to a parentheses. We still have places
|
|
|
|
// where it may be a block-level expression, so we need to
|
|
|
|
// generate an extra node that just propagates the value of the
|
|
|
|
// subexpression.
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
const Expr* Ex = U->getSubExpr()->IgnoreParens();
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
2010-06-27 06:40:52 +08:00
|
|
|
|
|
|
|
if (asLValue)
|
|
|
|
VisitLValue(Ex, Pred, Tmp);
|
|
|
|
else
|
|
|
|
Visit(Ex, Pred, Tmp);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
|
2009-02-13 09:45:31 +08:00
|
|
|
const GRState* state = GetState(*I);
|
2010-02-09 00:18:51 +08:00
|
|
|
MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex)));
|
2008-04-30 05:04:26 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
case UnaryOperator::AddrOf: {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-16 14:09:51 +08:00
|
|
|
assert(!asLValue);
|
2010-07-20 14:22:24 +08:00
|
|
|
const Expr* Ex = U->getSubExpr()->IgnoreParens();
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
2008-10-16 14:09:51 +08:00
|
|
|
VisitLValue(Ex, Pred, Tmp);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
|
2009-02-13 09:45:31 +08:00
|
|
|
const GRState* state = GetState(*I);
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal V = state->getSVal(Ex);
|
2009-08-28 06:17:37 +08:00
|
|
|
state = state->BindExpr(U, V);
|
2009-02-13 09:45:31 +08:00
|
|
|
MakeNode(Dst, U, *I, state);
|
2008-02-22 03:15:37 +08:00
|
|
|
}
|
2008-02-22 02:02:17 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
return;
|
2008-04-30 05:04:26 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
case UnaryOperator::LNot:
|
|
|
|
case UnaryOperator::Minus:
|
|
|
|
case UnaryOperator::Not: {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-16 14:09:51 +08:00
|
|
|
assert (!asLValue);
|
2010-07-20 14:22:24 +08:00
|
|
|
const Expr* Ex = U->getSubExpr()->IgnoreParens();
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
2008-04-30 05:04:26 +08:00
|
|
|
Visit(Ex, Pred, Tmp);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
|
2009-02-13 09:45:31 +08:00
|
|
|
const GRState* state = GetState(*I);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-09-30 13:32:44 +08:00
|
|
|
// Get the value of the subexpression.
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal V = state->getSVal(Ex);
|
2008-09-30 13:32:44 +08:00
|
|
|
|
2008-11-15 08:20:05 +08:00
|
|
|
if (V.isUnknownOrUndef()) {
|
2009-08-28 06:17:37 +08:00
|
|
|
MakeNode(Dst, U, *I, state->BindExpr(U, V));
|
2008-11-15 08:20:05 +08:00
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-11-15 12:01:56 +08:00
|
|
|
// QualType DstT = getContext().getCanonicalType(U->getType());
|
|
|
|
// QualType SrcT = getContext().getCanonicalType(Ex->getType());
|
2009-09-09 23:08:12 +08:00
|
|
|
//
|
2008-11-15 12:01:56 +08:00
|
|
|
// if (DstT != SrcT) // Perform promotions.
|
2009-09-09 23:08:12 +08:00
|
|
|
// V = EvalCast(V, DstT);
|
|
|
|
//
|
2008-11-15 12:01:56 +08:00
|
|
|
// if (V.isUnknownOrUndef()) {
|
|
|
|
// MakeNode(Dst, U, *I, BindExpr(St, U, V));
|
|
|
|
// continue;
|
|
|
|
// }
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
switch (U->getOpcode()) {
|
|
|
|
default:
|
|
|
|
assert(false && "Invalid Opcode.");
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
case UnaryOperator::Not:
|
2008-10-01 08:21:14 +08:00
|
|
|
// FIXME: Do we need to handle promotions?
|
2009-08-28 06:17:37 +08:00
|
|
|
state = state->BindExpr(U, EvalComplement(cast<NonLoc>(V)));
|
2009-09-09 23:08:12 +08:00
|
|
|
break;
|
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
case UnaryOperator::Minus:
|
2008-10-01 08:21:14 +08:00
|
|
|
// FIXME: Do we need to handle promotions?
|
2009-08-28 06:17:37 +08:00
|
|
|
state = state->BindExpr(U, EvalMinus(cast<NonLoc>(V)));
|
2009-09-09 23:08:12 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case UnaryOperator::LNot:
|
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
// C99 6.5.3.3: "The expression !E is equivalent to (0==E)."
|
|
|
|
//
|
|
|
|
// Note: technically we do "E == 0", but this is the same in the
|
|
|
|
// transfer functions as "0 == E".
|
2009-06-26 08:05:51 +08:00
|
|
|
SVal Result;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-17 13:57:07 +08:00
|
|
|
if (isa<Loc>(V)) {
|
2009-06-23 17:02:15 +08:00
|
|
|
Loc X = ValMgr.makeNull();
|
2009-06-26 08:05:51 +08:00
|
|
|
Result = EvalBinOp(state, BinaryOperator::EQ, cast<Loc>(V), X,
|
|
|
|
U->getType());
|
2008-04-30 05:04:26 +08:00
|
|
|
}
|
|
|
|
else {
|
2008-11-15 12:01:56 +08:00
|
|
|
nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType()));
|
2009-10-06 09:39:48 +08:00
|
|
|
Result = EvalBinOp(state, BinaryOperator::EQ, cast<NonLoc>(V), X,
|
2009-06-26 08:05:51 +08:00
|
|
|
U->getType());
|
2008-04-30 05:04:26 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-28 06:17:37 +08:00
|
|
|
state = state->BindExpr(U, Result);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
break;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-13 09:45:31 +08:00
|
|
|
MakeNode(Dst, U, *I, state);
|
2008-04-30 05:04:26 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
return;
|
|
|
|
}
|
2008-01-24 10:28:56 +08:00
|
|
|
}
|
2008-02-27 15:04:16 +08:00
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
// Handle ++ and -- (both pre- and post-increment).
|
2008-04-22 07:43:38 +08:00
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
assert (U->isIncrementDecrementOp());
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
2010-07-20 14:22:24 +08:00
|
|
|
const Expr* Ex = U->getSubExpr()->IgnoreParens();
|
2008-10-16 14:09:51 +08:00
|
|
|
VisitLValue(Ex, Pred, Tmp);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-13 09:45:31 +08:00
|
|
|
const GRState* state = GetState(*I);
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal V1 = state->getSVal(Ex);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
// Perform a load.
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp2;
|
2009-02-13 09:45:31 +08:00
|
|
|
EvalLoad(Tmp2, Ex, *I, state, V1);
|
2008-04-22 12:56:29 +08:00
|
|
|
|
2009-12-16 19:27:52 +08:00
|
|
|
for (ExplodedNodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end();I2!=E2;++I2) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-13 09:45:31 +08:00
|
|
|
state = GetState(*I2);
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal V2_untested = state->getSVal(Ex);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
// Propagate unknown and undefined values.
|
2009-09-12 06:07:28 +08:00
|
|
|
if (V2_untested.isUnknownOrUndef()) {
|
|
|
|
MakeNode(Dst, U, *I2, state->BindExpr(U, V2_untested));
|
2008-04-30 05:04:26 +08:00
|
|
|
continue;
|
2010-02-16 07:02:46 +08:00
|
|
|
}
|
2009-09-12 06:07:28 +08:00
|
|
|
DefinedSVal V2 = cast<DefinedSVal>(V2_untested);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
// Handle all other values.
|
2008-04-30 05:04:26 +08:00
|
|
|
BinaryOperator::Opcode Op = U->isIncrementOp() ? BinaryOperator::Add
|
|
|
|
: BinaryOperator::Sub;
|
2009-03-11 11:54:24 +08:00
|
|
|
|
2009-08-05 10:51:59 +08:00
|
|
|
// If the UnaryOperator has non-location type, use its type to create the
|
|
|
|
// constant value. If the UnaryOperator has location type, create the
|
|
|
|
// constant with int type and pointer width.
|
|
|
|
SVal RHS;
|
|
|
|
|
|
|
|
if (U->getType()->isAnyPointerType())
|
|
|
|
RHS = ValMgr.makeIntValWithPtrWidth(1, false);
|
|
|
|
else
|
|
|
|
RHS = ValMgr.makeIntVal(1, U->getType());
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
SVal Result = EvalBinOp(state, Op, V2, RHS, U->getType());
|
|
|
|
|
2009-03-21 04:10:45 +08:00
|
|
|
// Conjure a new symbol if necessary to recover precision.
|
2009-04-22 06:38:05 +08:00
|
|
|
if (Result.isUnknown() || !getConstraintManager().canReasonAbout(Result)){
|
2009-09-12 06:07:28 +08:00
|
|
|
DefinedOrUnknownSVal SymVal =
|
2009-09-28 04:45:21 +08:00
|
|
|
ValMgr.getConjuredSymbolVal(NULL, Ex,
|
|
|
|
Builder->getCurrentBlockCount());
|
2009-09-12 06:07:28 +08:00
|
|
|
Result = SymVal;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-04-22 06:38:05 +08:00
|
|
|
// If the value is a location, ++/-- should always preserve
|
2009-06-26 08:05:51 +08:00
|
|
|
// non-nullness. Check if the original value was non-null, and if so
|
2009-09-09 23:08:12 +08:00
|
|
|
// propagate that constraint.
|
2009-04-22 06:38:05 +08:00
|
|
|
if (Loc::IsLocType(U->getType())) {
|
2009-09-12 06:07:28 +08:00
|
|
|
DefinedOrUnknownSVal Constraint =
|
|
|
|
SVator.EvalEQ(state, V2, ValMgr.makeZeroVal(U->getType()));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-12 06:07:28 +08:00
|
|
|
if (!state->Assume(Constraint, true)) {
|
2009-04-22 06:38:05 +08:00
|
|
|
// It isn't feasible for the original value to be null.
|
|
|
|
// Propagate this constraint.
|
2009-09-12 06:07:28 +08:00
|
|
|
Constraint = SVator.EvalEQ(state, SymVal,
|
|
|
|
ValMgr.makeZeroVal(U->getType()));
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-12 06:07:28 +08:00
|
|
|
state = state->Assume(Constraint, false);
|
2009-06-19 06:57:13 +08:00
|
|
|
assert(state);
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
|
|
|
}
|
2009-04-22 06:38:05 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-28 06:17:37 +08:00
|
|
|
state = state->BindExpr(U, U->isPostfix() ? V2 : Result);
|
2008-04-30 05:04:26 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
// Perform the store.
|
2009-11-05 08:42:23 +08:00
|
|
|
EvalStore(Dst, NULL, U, *I2, state, V1, Result);
|
2008-02-07 09:08:27 +08:00
|
|
|
}
|
2008-04-22 07:43:38 +08:00
|
|
|
}
|
2008-02-07 09:08:27 +08:00
|
|
|
}
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitAsmStmt(const AsmStmt* A, ExplodedNode* Pred,
|
2009-12-16 19:27:52 +08:00
|
|
|
ExplodedNodeSet& Dst) {
|
2008-03-18 05:11:24 +08:00
|
|
|
VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst);
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2008-03-18 05:11:24 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitAsmStmtHelperOutputs(const AsmStmt* A,
|
|
|
|
AsmStmt::const_outputs_iterator I,
|
|
|
|
AsmStmt::const_outputs_iterator E,
|
2009-12-16 19:27:52 +08:00
|
|
|
ExplodedNode* Pred, ExplodedNodeSet& Dst) {
|
2008-03-18 05:11:24 +08:00
|
|
|
if (I == E) {
|
|
|
|
VisitAsmStmtHelperInputs(A, A->begin_inputs(), A->end_inputs(), Pred, Dst);
|
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
2008-10-16 14:09:51 +08:00
|
|
|
VisitLValue(*I, Pred, Tmp);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-18 05:11:24 +08:00
|
|
|
++I;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-12-16 19:27:52 +08:00
|
|
|
for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end();NI != NE;++NI)
|
2008-03-18 05:11:24 +08:00
|
|
|
VisitAsmStmtHelperOutputs(A, I, E, *NI, Dst);
|
|
|
|
}
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitAsmStmtHelperInputs(const AsmStmt* A,
|
|
|
|
AsmStmt::const_inputs_iterator I,
|
|
|
|
AsmStmt::const_inputs_iterator E,
|
2010-02-16 07:02:46 +08:00
|
|
|
ExplodedNode* Pred,
|
2009-12-16 19:27:52 +08:00
|
|
|
ExplodedNodeSet& Dst) {
|
2008-03-18 05:11:24 +08:00
|
|
|
if (I == E) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-18 05:11:24 +08:00
|
|
|
// We have processed both the inputs and the outputs. All of the outputs
|
2008-10-17 13:57:07 +08:00
|
|
|
// should evaluate to Locs. Nuke all of their values.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-18 05:11:24 +08:00
|
|
|
// FIXME: Some day in the future it would be nice to allow a "plug-in"
|
|
|
|
// which interprets the inline asm and stores proper results in the
|
|
|
|
// outputs.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-13 09:45:31 +08:00
|
|
|
const GRState* state = GetState(Pred);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
for (AsmStmt::const_outputs_iterator OI = A->begin_outputs(),
|
2008-03-18 05:11:24 +08:00
|
|
|
OE = A->end_outputs(); OI != OE; ++OI) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal X = state->getSVal(*OI);
|
2008-10-17 13:57:07 +08:00
|
|
|
assert (!isa<NonLoc>(X)); // Should be an Lval, or unknown, undef.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-17 13:57:07 +08:00
|
|
|
if (isa<Loc>(X))
|
2009-06-20 01:10:32 +08:00
|
|
|
state = state->bindLoc(cast<Loc>(X), UnknownVal());
|
2008-03-18 05:11:24 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-13 09:45:31 +08:00
|
|
|
MakeNode(Dst, A, Pred, state);
|
2008-03-18 05:11:24 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp;
|
2008-03-18 05:11:24 +08:00
|
|
|
Visit(*I, Pred, Tmp);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-18 05:11:24 +08:00
|
|
|
++I;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-03 11:02:58 +08:00
|
|
|
for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI!=NE; ++NI)
|
2008-03-18 05:11:24 +08:00
|
|
|
VisitAsmStmtHelperInputs(A, I, E, *NI, Dst);
|
|
|
|
}
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred,
|
2009-11-06 10:24:13 +08:00
|
|
|
ExplodedNodeSet &Dst) {
|
|
|
|
ExplodedNodeSet Src;
|
2010-07-20 14:22:24 +08:00
|
|
|
if (const Expr *RetE = RS->getRetValue()) {
|
2010-03-23 16:09:29 +08:00
|
|
|
// Record the returned expression in the state. It will be used in
|
|
|
|
// ProcessCallExit to bind the return value to the call expr.
|
2010-02-26 23:43:34 +08:00
|
|
|
{
|
2010-03-03 05:43:52 +08:00
|
|
|
static int Tag = 0;
|
|
|
|
SaveAndRestore<const void *> OldTag(Builder->Tag, &Tag);
|
2010-02-26 23:43:34 +08:00
|
|
|
const GRState *state = GetState(Pred);
|
|
|
|
state = state->set<ReturnExpr>(RetE);
|
|
|
|
Pred = Builder->generateNode(RetE, state, Pred);
|
|
|
|
}
|
|
|
|
// We may get a NULL Pred because we generated a cached node.
|
|
|
|
if (Pred)
|
|
|
|
Visit(RetE, Pred, Src);
|
2008-03-31 23:02:58 +08:00
|
|
|
}
|
2009-11-06 10:24:13 +08:00
|
|
|
else {
|
|
|
|
Src.Add(Pred);
|
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-06 10:24:13 +08:00
|
|
|
ExplodedNodeSet CheckedSet;
|
|
|
|
CheckerVisit(RS, CheckedSet, Src, true);
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-06 10:24:13 +08:00
|
|
|
for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
|
|
|
|
I != E; ++I) {
|
2008-04-17 07:05:51 +08:00
|
|
|
|
2009-11-06 10:24:13 +08:00
|
|
|
assert(Builder && "GRStmtNodeBuilder must be defined.");
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-06 10:24:13 +08:00
|
|
|
Pred = *I;
|
|
|
|
unsigned size = Dst.size();
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-06 10:24:13 +08:00
|
|
|
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
|
|
|
|
SaveOr OldHasGen(Builder->HasGeneratedNode);
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-06 10:24:13 +08:00
|
|
|
getTF().EvalReturn(Dst, *this, *Builder, RS, Pred);
|
2010-02-16 07:02:46 +08:00
|
|
|
|
|
|
|
// Handle the case where no nodes where generated.
|
|
|
|
if (!Builder->BuildSinks && Dst.size() == size &&
|
2009-11-06 10:24:13 +08:00
|
|
|
!Builder->HasGeneratedNode)
|
|
|
|
MakeNode(Dst, RS, Pred, GetState(Pred));
|
2008-11-21 08:27:44 +08:00
|
|
|
}
|
2008-03-31 23:02:58 +08:00
|
|
|
}
|
2008-03-25 08:34:37 +08:00
|
|
|
|
2008-04-16 07:06:53 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Transfer functions: Binary operators.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
void GRExprEngine::VisitBinaryOperator(const BinaryOperator* B,
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNode* Pred,
|
2009-10-30 15:19:39 +08:00
|
|
|
ExplodedNodeSet& Dst, bool asLValue) {
|
2008-04-30 05:04:26 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp1;
|
2008-04-30 05:04:26 +08:00
|
|
|
Expr* LHS = B->getLHS()->IgnoreParens();
|
|
|
|
Expr* RHS = B->getRHS()->IgnoreParens();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-21 01:02:02 +08:00
|
|
|
// FIXME: Add proper support for ObjCImplicitSetterGetterRefExpr.
|
|
|
|
if (isa<ObjCImplicitSetterGetterRefExpr>(LHS)) {
|
2009-09-09 23:08:12 +08:00
|
|
|
Visit(RHS, Pred, Dst);
|
2008-12-06 10:39:30 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-07 09:08:27 +08:00
|
|
|
if (B->isAssignmentOp())
|
2008-10-16 14:09:51 +08:00
|
|
|
VisitLValue(LHS, Pred, Tmp1);
|
2008-02-07 09:08:27 +08:00
|
|
|
else
|
2008-04-30 05:04:26 +08:00
|
|
|
Visit(LHS, Pred, Tmp1);
|
2008-01-16 08:53:15 +08:00
|
|
|
|
2009-11-24 16:24:26 +08:00
|
|
|
ExplodedNodeSet Tmp3;
|
|
|
|
|
2009-09-03 11:02:58 +08:00
|
|
|
for (ExplodedNodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1!=E1; ++I1) {
|
2010-04-20 12:53:09 +08:00
|
|
|
SVal LeftV = GetState(*I1)->getSVal(LHS);
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNodeSet Tmp2;
|
2008-04-30 05:04:26 +08:00
|
|
|
Visit(RHS, *I1, Tmp2);
|
2009-09-02 21:26:26 +08:00
|
|
|
|
|
|
|
ExplodedNodeSet CheckedSet;
|
|
|
|
CheckerVisit(B, CheckedSet, Tmp2, true);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
// With both the LHS and RHS evaluated, process the operation itself.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
for (ExplodedNodeSet::iterator I2=CheckedSet.begin(), E2=CheckedSet.end();
|
2009-09-02 21:26:26 +08:00
|
|
|
I2 != E2; ++I2) {
|
2008-02-07 06:50:25 +08:00
|
|
|
|
2009-09-12 06:07:28 +08:00
|
|
|
const GRState *state = GetState(*I2);
|
|
|
|
const GRState *OldSt = state;
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal RightV = state->getSVal(RHS);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-12 06:07:28 +08:00
|
|
|
BinaryOperator::Opcode Op = B->getOpcode();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-10-21 19:42:22 +08:00
|
|
|
if (Op == BinaryOperator::Assign) {
|
|
|
|
// EXPERIMENTAL: "Conjured" symbols.
|
|
|
|
// FIXME: Handle structs.
|
|
|
|
QualType T = RHS->getType();
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-10-21 19:42:22 +08:00
|
|
|
if ((RightV.isUnknown()||!getConstraintManager().canReasonAbout(RightV))
|
|
|
|
&& (Loc::IsLocType(T) || (T->isScalarType()&&T->isIntegerType()))) {
|
|
|
|
unsigned Count = Builder->getCurrentBlockCount();
|
|
|
|
RightV = ValMgr.getConjuredSymbolVal(NULL, B->getRHS(), Count);
|
2008-01-24 03:59:44 +08:00
|
|
|
}
|
2009-10-30 15:19:39 +08:00
|
|
|
|
2009-10-31 06:01:29 +08:00
|
|
|
SVal ExprVal = asLValue ? LeftV : RightV;
|
2009-10-30 15:19:39 +08:00
|
|
|
|
2009-10-21 19:42:22 +08:00
|
|
|
// Simulate the effects of a "store": bind the value of the RHS
|
|
|
|
// to the L-Value represented by the LHS.
|
2009-12-16 19:27:52 +08:00
|
|
|
EvalStore(Tmp3, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV,RightV);
|
2009-10-21 19:42:22 +08:00
|
|
|
continue;
|
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-10-21 19:42:22 +08:00
|
|
|
if (!B->isAssignmentOp()) {
|
|
|
|
// Process non-assignments except commas or short-circuited
|
|
|
|
// logical expressions (LAnd and LOr).
|
|
|
|
SVal Result = EvalBinOp(state, Op, LeftV, RightV, B->getType());
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-10-21 19:42:22 +08:00
|
|
|
if (Result.isUnknown()) {
|
|
|
|
if (OldSt != state) {
|
|
|
|
// Generate a new node if we have already created a new state.
|
2009-11-24 16:24:26 +08:00
|
|
|
MakeNode(Tmp3, B, *I2, state);
|
2008-02-22 02:02:17 +08:00
|
|
|
}
|
2009-10-21 19:42:22 +08:00
|
|
|
else
|
2009-11-24 16:24:26 +08:00
|
|
|
Tmp3.Add(*I2);
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-10-21 19:42:22 +08:00
|
|
|
continue;
|
|
|
|
}
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-10-21 19:42:22 +08:00
|
|
|
state = state->BindExpr(B, Result);
|
2010-02-16 07:02:46 +08:00
|
|
|
|
2009-11-24 16:24:26 +08:00
|
|
|
MakeNode(Tmp3, B, *I2, state);
|
2009-10-21 19:42:22 +08:00
|
|
|
continue;
|
2008-04-30 05:04:26 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
assert (B->isCompoundAssignmentOp());
|
|
|
|
|
2009-02-07 08:52:24 +08:00
|
|
|
switch (Op) {
|
|
|
|
default:
|
|
|
|
assert(0 && "Invalid opcode for compound assignment.");
|
|
|
|
case BinaryOperator::MulAssign: Op = BinaryOperator::Mul; break;
|
|
|
|
case BinaryOperator::DivAssign: Op = BinaryOperator::Div; break;
|
|
|
|
case BinaryOperator::RemAssign: Op = BinaryOperator::Rem; break;
|
|
|
|
case BinaryOperator::AddAssign: Op = BinaryOperator::Add; break;
|
|
|
|
case BinaryOperator::SubAssign: Op = BinaryOperator::Sub; break;
|
|
|
|
case BinaryOperator::ShlAssign: Op = BinaryOperator::Shl; break;
|
|
|
|
case BinaryOperator::ShrAssign: Op = BinaryOperator::Shr; break;
|
|
|
|
case BinaryOperator::AndAssign: Op = BinaryOperator::And; break;
|
|
|
|
case BinaryOperator::XorAssign: Op = BinaryOperator::Xor; break;
|
|
|
|
case BinaryOperator::OrAssign: Op = BinaryOperator::Or; break;
|
2008-10-28 07:02:39 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-30 05:04:26 +08:00
|
|
|
// Perform a load (the LHS). This performs the checks for
|
|
|
|
// null dereferences, and so on.
|
2010-01-19 17:25:53 +08:00
|
|
|
ExplodedNodeSet Tmp4;
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal location = state->getSVal(LHS);
|
2010-01-19 17:25:53 +08:00
|
|
|
EvalLoad(Tmp4, LHS, *I2, state, location);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-01-19 17:25:53 +08:00
|
|
|
for (ExplodedNodeSet::iterator I4=Tmp4.begin(), E4=Tmp4.end(); I4!=E4;
|
|
|
|
++I4) {
|
|
|
|
state = GetState(*I4);
|
2010-02-09 00:18:51 +08:00
|
|
|
SVal V = state->getSVal(LHS);
|
2008-04-30 05:04:26 +08:00
|
|
|
|
|
|
|
// Get the computation type.
|
2009-07-22 05:03:30 +08:00
|
|
|
QualType CTy =
|
|
|
|
cast<CompoundAssignOperator>(B)->getComputationResultType();
|
2008-11-15 12:01:56 +08:00
|
|
|
CTy = getContext().getCanonicalType(CTy);
|
2009-03-28 09:22:36 +08:00
|
|
|
|
2009-07-22 05:03:30 +08:00
|
|
|
QualType CLHSTy =
|
|
|
|
cast<CompoundAssignOperator>(B)->getComputationLHSType();
|
|
|
|
CLHSTy = getContext().getCanonicalType(CLHSTy);
|
2009-03-28 09:22:36 +08:00
|
|
|
|
2008-11-15 12:01:56 +08:00
|
|
|
QualType LTy = getContext().getCanonicalType(LHS->getType());
|
|
|
|
QualType RTy = getContext().getCanonicalType(RHS->getType());
|
2009-03-28 09:22:36 +08:00
|
|
|
|
|
|
|
// Promote LHS.
|
2010-02-04 12:56:43 +08:00
|
|
|
V = SVator.EvalCast(V, CLHSTy, LTy);
|
2009-03-28 09:22:36 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
// Compute the result of the operation.
|
2010-02-04 12:56:43 +08:00
|
|
|
SVal Result = SVator.EvalCast(EvalBinOp(state, Op, V, RightV, CTy),
|
|
|
|
B->getType(), CTy);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-21 07:13:25 +08:00
|
|
|
// EXPERIMENTAL: "Conjured" symbols.
|
|
|
|
// FIXME: Handle structs.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-11-15 12:01:56 +08:00
|
|
|
SVal LHSVal;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
if ((Result.isUnknown() ||
|
2009-03-11 10:24:48 +08:00
|
|
|
!getConstraintManager().canReasonAbout(Result))
|
2009-09-09 23:08:12 +08:00
|
|
|
&& (Loc::IsLocType(CTy)
|
2009-03-11 10:24:48 +08:00
|
|
|
|| (CTy->isScalarType() && CTy->isIntegerType()))) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-21 07:13:25 +08:00
|
|
|
unsigned Count = Builder->getCurrentBlockCount();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-11-15 12:01:56 +08:00
|
|
|
// The symbolic value is actually for the type of the left-hand side
|
|
|
|
// expression, not the computation type, as this is the value the
|
|
|
|
// LValue on the LHS will bind to.
|
2009-09-28 04:45:21 +08:00
|
|
|
LHSVal = ValMgr.getConjuredSymbolVal(NULL, B->getRHS(), LTy, Count);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-11-23 13:52:28 +08:00
|
|
|
// However, we need to convert the symbol to the computation type.
|
2010-02-04 12:56:43 +08:00
|
|
|
Result = SVator.EvalCast(LHSVal, CTy, LTy);
|
2008-10-21 07:13:25 +08:00
|
|
|
}
|
2008-11-15 12:01:56 +08:00
|
|
|
else {
|
|
|
|
// The left-hand side may bind to a different value then the
|
|
|
|
// computation type.
|
2010-02-04 12:56:43 +08:00
|
|
|
LHSVal = SVator.EvalCast(Result, LTy, CTy);
|
2008-11-15 12:01:56 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-01-19 17:25:53 +08:00
|
|
|
EvalStore(Tmp3, B, LHS, *I4, state->BindExpr(B, Result),
|
2009-08-25 14:51:30 +08:00
|
|
|
location, LHSVal);
|
2008-01-24 03:59:44 +08:00
|
|
|
}
|
2008-01-16 08:53:15 +08:00
|
|
|
}
|
2008-01-16 07:55:06 +08:00
|
|
|
}
|
2009-11-24 16:24:26 +08:00
|
|
|
|
|
|
|
CheckerVisit(B, Dst, Tmp3, false);
|
2008-01-16 07:55:06 +08:00
|
|
|
}
|
|
|
|
|
2009-10-31 01:47:32 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Checker registration/lookup.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
Checker *GRExprEngine::lookupChecker(void *tag) const {
|
2009-11-10 09:17:45 +08:00
|
|
|
CheckerMap::const_iterator I = CheckerM.find(tag);
|
2009-10-31 01:47:32 +08:00
|
|
|
return (I == CheckerM.end()) ? NULL : Checkers[I->second].second;
|
|
|
|
}
|
|
|
|
|
2008-07-18 05:27:31 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2008-02-15 06:36:46 +08:00
|
|
|
// Visualization.
|
2008-01-17 02:18:48 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2008-01-17 05:46:15 +08:00
|
|
|
#ifndef NDEBUG
|
2008-02-14 01:41:41 +08:00
|
|
|
static GRExprEngine* GraphPrintCheckerState;
|
2008-03-08 04:57:30 +08:00
|
|
|
static SourceManager* GraphPrintSourceManager;
|
2008-01-31 07:24:39 +08:00
|
|
|
|
2008-01-17 05:46:15 +08:00
|
|
|
namespace llvm {
|
|
|
|
template<>
|
2009-12-01 00:08:24 +08:00
|
|
|
struct DOTGraphTraits<ExplodedNode*> :
|
2008-01-17 05:46:15 +08:00
|
|
|
public DefaultDOTGraphTraits {
|
2009-11-30 22:16:05 +08:00
|
|
|
|
|
|
|
DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
|
|
|
|
|
2009-10-29 10:09:30 +08:00
|
|
|
// FIXME: Since we do not cache error nodes in GRExprEngine now, this does not
|
|
|
|
// work.
|
2009-08-06 20:48:26 +08:00
|
|
|
static std::string getNodeAttributes(const ExplodedNode* N, void*) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-12 04:16:36 +08:00
|
|
|
#if 0
|
|
|
|
// FIXME: Replace with a general scheme to tell if the node is
|
|
|
|
// an error node.
|
2008-02-15 06:54:53 +08:00
|
|
|
if (GraphPrintCheckerState->isImplicitNullDeref(N) ||
|
2008-02-19 08:22:37 +08:00
|
|
|
GraphPrintCheckerState->isExplicitNullDeref(N) ||
|
2008-02-28 17:25:22 +08:00
|
|
|
GraphPrintCheckerState->isUndefDeref(N) ||
|
|
|
|
GraphPrintCheckerState->isUndefStore(N) ||
|
|
|
|
GraphPrintCheckerState->isUndefControlFlow(N) ||
|
2008-03-01 07:14:48 +08:00
|
|
|
GraphPrintCheckerState->isUndefResult(N) ||
|
2008-03-01 07:53:11 +08:00
|
|
|
GraphPrintCheckerState->isBadCall(N) ||
|
|
|
|
GraphPrintCheckerState->isUndefArg(N))
|
2008-02-15 06:54:53 +08:00
|
|
|
return "color=\"red\",style=\"filled\"";
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-29 04:32:03 +08:00
|
|
|
if (GraphPrintCheckerState->isNoReturnCall(N))
|
|
|
|
return "color=\"blue\",style=\"filled\"";
|
2009-11-24 15:06:39 +08:00
|
|
|
#endif
|
2008-02-15 06:54:53 +08:00
|
|
|
return "";
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-30 22:16:05 +08:00
|
|
|
static std::string getNodeLabel(const ExplodedNode* N, void*){
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-25 07:06:47 +08:00
|
|
|
std::string sbuf;
|
|
|
|
llvm::raw_string_ostream Out(sbuf);
|
2008-01-24 06:30:44 +08:00
|
|
|
|
|
|
|
// Program Location.
|
2008-01-17 05:46:15 +08:00
|
|
|
ProgramPoint Loc = N->getLocation();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-17 05:46:15 +08:00
|
|
|
switch (Loc.getKind()) {
|
|
|
|
case ProgramPoint::BlockEntranceKind:
|
2009-09-09 23:08:12 +08:00
|
|
|
Out << "Block Entrance: B"
|
2008-01-17 05:46:15 +08:00
|
|
|
<< cast<BlockEntrance>(Loc).getBlock()->getBlockID();
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-17 05:46:15 +08:00
|
|
|
case ProgramPoint::BlockExitKind:
|
|
|
|
assert (false);
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-02-26 03:01:53 +08:00
|
|
|
case ProgramPoint::CallEnterKind:
|
|
|
|
Out << "CallEnter";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ProgramPoint::CallExitKind:
|
|
|
|
Out << "CallExit";
|
|
|
|
break;
|
|
|
|
|
2008-01-17 05:46:15 +08:00
|
|
|
default: {
|
2009-07-23 06:35:28 +08:00
|
|
|
if (StmtPoint *L = dyn_cast<StmtPoint>(&Loc)) {
|
|
|
|
const Stmt* S = L->getStmt();
|
2008-12-17 06:02:27 +08:00
|
|
|
SourceLocation SLoc = S->getLocStart();
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
Out << S->getStmtClassName() << ' ' << (void*) S << ' ';
|
2009-06-30 09:26:17 +08:00
|
|
|
LangOptions LO; // FIXME.
|
|
|
|
S->printPretty(Out, 0, PrintingPolicy(LO));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
if (SLoc.isFileID()) {
|
2008-12-17 06:02:27 +08:00
|
|
|
Out << "\\lline="
|
2009-02-04 08:55:58 +08:00
|
|
|
<< GraphPrintSourceManager->getInstantiationLineNumber(SLoc)
|
|
|
|
<< " col="
|
|
|
|
<< GraphPrintSourceManager->getInstantiationColumnNumber(SLoc)
|
|
|
|
<< "\\l";
|
2008-12-17 06:02:27 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-23 06:35:28 +08:00
|
|
|
if (isa<PreStmt>(Loc))
|
2009-09-09 23:08:12 +08:00
|
|
|
Out << "\\lPreStmt\\l;";
|
2009-07-23 06:35:28 +08:00
|
|
|
else if (isa<PostLoad>(Loc))
|
2009-05-08 02:27:16 +08:00
|
|
|
Out << "\\lPostLoad\\l;";
|
|
|
|
else if (isa<PostStore>(Loc))
|
|
|
|
Out << "\\lPostStore\\l";
|
|
|
|
else if (isa<PostLValue>(Loc))
|
|
|
|
Out << "\\lPostLValue\\l";
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-12 04:16:36 +08:00
|
|
|
#if 0
|
|
|
|
// FIXME: Replace with a general scheme to determine
|
|
|
|
// the name of the check.
|
2008-12-17 06:02:27 +08:00
|
|
|
if (GraphPrintCheckerState->isImplicitNullDeref(N))
|
|
|
|
Out << "\\|Implicit-Null Dereference.\\l";
|
|
|
|
else if (GraphPrintCheckerState->isExplicitNullDeref(N))
|
|
|
|
Out << "\\|Explicit-Null Dereference.\\l";
|
|
|
|
else if (GraphPrintCheckerState->isUndefDeref(N))
|
|
|
|
Out << "\\|Dereference of undefialied value.\\l";
|
|
|
|
else if (GraphPrintCheckerState->isUndefStore(N))
|
|
|
|
Out << "\\|Store to Undefined Loc.";
|
|
|
|
else if (GraphPrintCheckerState->isUndefResult(N))
|
|
|
|
Out << "\\|Result of operation is undefined.";
|
|
|
|
else if (GraphPrintCheckerState->isNoReturnCall(N))
|
|
|
|
Out << "\\|Call to function marked \"noreturn\".";
|
|
|
|
else if (GraphPrintCheckerState->isBadCall(N))
|
|
|
|
Out << "\\|Call to NULL/Undefined.";
|
|
|
|
else if (GraphPrintCheckerState->isUndefArg(N))
|
|
|
|
Out << "\\|Argument in call is undefined";
|
2009-11-12 04:16:36 +08:00
|
|
|
#endif
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-12-17 06:02:27 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-01-17 05:46:15 +08:00
|
|
|
const BlockEdge& E = cast<BlockEdge>(Loc);
|
|
|
|
Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B"
|
|
|
|
<< E.getDst()->getBlockID() << ')';
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
if (const Stmt* T = E.getSrc()->getTerminator()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-08 04:57:30 +08:00
|
|
|
SourceLocation SLoc = T->getLocStart();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-31 07:03:39 +08:00
|
|
|
Out << "\\|Terminator: ";
|
2009-06-30 09:26:17 +08:00
|
|
|
LangOptions LO; // FIXME.
|
|
|
|
E.getSrc()->printTerminator(Out, LO);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-09 11:30:59 +08:00
|
|
|
if (SLoc.isFileID()) {
|
|
|
|
Out << "\\lline="
|
2009-02-04 08:55:58 +08:00
|
|
|
<< GraphPrintSourceManager->getInstantiationLineNumber(SLoc)
|
|
|
|
<< " col="
|
|
|
|
<< GraphPrintSourceManager->getInstantiationColumnNumber(SLoc);
|
2008-03-09 11:30:59 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-14 07:08:21 +08:00
|
|
|
if (isa<SwitchStmt>(T)) {
|
2010-07-20 14:22:24 +08:00
|
|
|
const Stmt* Label = E.getDst()->getLabel();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
if (Label) {
|
2010-07-20 14:22:24 +08:00
|
|
|
if (const CaseStmt* C = dyn_cast<CaseStmt>(Label)) {
|
2008-02-14 07:08:21 +08:00
|
|
|
Out << "\\lcase ";
|
2009-06-30 09:26:17 +08:00
|
|
|
LangOptions LO; // FIXME.
|
|
|
|
C->getLHS()->printPretty(Out, 0, PrintingPolicy(LO));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-20 14:22:24 +08:00
|
|
|
if (const Stmt* RHS = C->getRHS()) {
|
2008-02-14 07:08:21 +08:00
|
|
|
Out << " .. ";
|
2009-06-30 09:26:17 +08:00
|
|
|
RHS->printPretty(Out, 0, PrintingPolicy(LO));
|
2008-02-14 07:08:21 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-14 07:08:21 +08:00
|
|
|
Out << ":";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
assert (isa<DefaultStmt>(Label));
|
|
|
|
Out << "\\ldefault:";
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
else
|
2008-02-14 07:08:21 +08:00
|
|
|
Out << "\\l(implicit) default:";
|
|
|
|
}
|
|
|
|
else if (isa<IndirectGotoStmt>(T)) {
|
2008-01-31 07:03:39 +08:00
|
|
|
// FIXME
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Out << "\\lCondition: ";
|
|
|
|
if (*E.getSrc()->succ_begin() == E.getDst())
|
|
|
|
Out << "true";
|
|
|
|
else
|
2009-09-09 23:08:12 +08:00
|
|
|
Out << "false";
|
2008-01-31 07:03:39 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-31 07:03:39 +08:00
|
|
|
Out << "\\l";
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-12 04:16:36 +08:00
|
|
|
#if 0
|
|
|
|
// FIXME: Replace with a general scheme to determine
|
|
|
|
// the name of the check.
|
2008-02-28 17:25:22 +08:00
|
|
|
if (GraphPrintCheckerState->isUndefControlFlow(N)) {
|
|
|
|
Out << "\\|Control-flow based on\\lUndefined value.\\l";
|
2008-01-31 07:24:39 +08:00
|
|
|
}
|
2009-11-12 04:16:36 +08:00
|
|
|
#endif
|
2008-01-17 05:46:15 +08:00
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-28 18:21:43 +08:00
|
|
|
Out << "\\|StateID: " << (void*) N->getState() << "\\|";
|
2008-02-09 05:10:02 +08:00
|
|
|
|
2009-06-18 09:23:53 +08:00
|
|
|
const GRState *state = N->getState();
|
2010-03-05 12:45:36 +08:00
|
|
|
state->printDOT(Out, *N->getLocationContext()->getCFG());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-24 06:30:44 +08:00
|
|
|
Out << "\\l";
|
2008-01-17 05:46:15 +08:00
|
|
|
return Out.str();
|
|
|
|
}
|
|
|
|
};
|
2009-09-09 23:08:12 +08:00
|
|
|
} // end llvm namespace
|
2008-01-17 05:46:15 +08:00
|
|
|
#endif
|
|
|
|
|
2008-03-08 06:58:01 +08:00
|
|
|
#ifndef NDEBUG
|
2008-03-13 01:18:20 +08:00
|
|
|
template <typename ITERATOR>
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNode* GetGraphNode(ITERATOR I) { return *I; }
|
2008-03-13 01:18:20 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
template <> ExplodedNode*
|
|
|
|
GetGraphNode<llvm::DenseMap<ExplodedNode*, Expr*>::iterator>
|
|
|
|
(llvm::DenseMap<ExplodedNode*, Expr*>::iterator I) {
|
2008-03-13 01:18:20 +08:00
|
|
|
return I->first;
|
|
|
|
}
|
2008-03-08 06:58:01 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
void GRExprEngine::ViewGraph(bool trim) {
|
2009-09-09 23:08:12 +08:00
|
|
|
#ifndef NDEBUG
|
2008-03-08 06:58:01 +08:00
|
|
|
if (trim) {
|
2009-08-06 20:48:26 +08:00
|
|
|
std::vector<ExplodedNode*> Src;
|
2009-03-11 09:41:22 +08:00
|
|
|
|
|
|
|
// Flush any outstanding reports to make sure we cover all the nodes.
|
|
|
|
// This does not cause them to get displayed.
|
|
|
|
for (BugReporter::iterator I=BR.begin(), E=BR.end(); I!=E; ++I)
|
|
|
|
const_cast<BugType*>(*I)->FlushReports(BR);
|
|
|
|
|
|
|
|
// Iterate through the reports and get their nodes.
|
|
|
|
for (BugReporter::iterator I=BR.begin(), E=BR.end(); I!=E; ++I) {
|
2009-09-03 11:02:58 +08:00
|
|
|
for (BugType::const_iterator I2=(*I)->begin(), E2=(*I)->end();
|
2009-09-09 23:08:12 +08:00
|
|
|
I2!=E2; ++I2) {
|
2009-03-11 09:41:22 +08:00
|
|
|
const BugReportEquivClass& EQ = *I2;
|
|
|
|
const BugReport &R = **EQ.begin();
|
2009-08-06 20:48:26 +08:00
|
|
|
ExplodedNode *N = const_cast<ExplodedNode*>(R.getEndNode());
|
2009-03-11 09:41:22 +08:00
|
|
|
if (N) Src.push_back(N);
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-13 01:18:20 +08:00
|
|
|
ViewGraph(&Src[0], &Src[0]+Src.size());
|
2008-03-08 06:58:01 +08:00
|
|
|
}
|
2008-03-12 02:25:33 +08:00
|
|
|
else {
|
|
|
|
GraphPrintCheckerState = this;
|
|
|
|
GraphPrintSourceManager = &getContext().getSourceManager();
|
2008-08-14 05:24:49 +08:00
|
|
|
|
2008-03-08 06:58:01 +08:00
|
|
|
llvm::ViewGraph(*G.roots_begin(), "GRExprEngine");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-12 02:25:33 +08:00
|
|
|
GraphPrintCheckerState = NULL;
|
|
|
|
GraphPrintSourceManager = NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
void GRExprEngine::ViewGraph(ExplodedNode** Beg, ExplodedNode** End) {
|
2008-03-12 02:25:33 +08:00
|
|
|
#ifndef NDEBUG
|
|
|
|
GraphPrintCheckerState = this;
|
|
|
|
GraphPrintSourceManager = &getContext().getSourceManager();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-06 20:48:26 +08:00
|
|
|
std::auto_ptr<ExplodedGraph> TrimmedG(G.Trim(Beg, End).first);
|
2008-03-12 02:25:33 +08:00
|
|
|
|
2009-02-05 07:49:09 +08:00
|
|
|
if (!TrimmedG.get())
|
2009-08-23 20:08:50 +08:00
|
|
|
llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n";
|
2009-02-05 07:49:09 +08:00
|
|
|
else
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::ViewGraph(*TrimmedG->roots_begin(), "TrimmedGRExprEngine");
|
|
|
|
|
2008-01-31 07:24:39 +08:00
|
|
|
GraphPrintCheckerState = NULL;
|
2008-03-08 04:57:30 +08:00
|
|
|
GraphPrintSourceManager = NULL;
|
2008-02-15 06:36:46 +08:00
|
|
|
#endif
|
2008-01-17 02:18:48 +08:00
|
|
|
}
|