"git@repo.hca.bsc.es:rferrer/llvm-epi-0.8.git" did not exist on "6dc9870556e09942326ce953d8508b6e33690cf8"
Newer
Older
// GRSimpleVals.cpp - Transfer functions for tracking simple values -*- C++ -*--
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines GRSimpleVals, a sub-class of GRTransferFuncs that
// provides transfer functions for performing simple value tracking with
// limited support for symbolics.
//
//===----------------------------------------------------------------------===//
#include "GRSimpleVals.h"
Ted Kremenek
committed
#include "BasicObjCFoundationChecks.h"
Ted Kremenek
committed
#include "clang/Analysis/PathSensitive/ValueState.h"
Ted Kremenek
committed
#include "clang/Analysis/PathDiagnostic.h"
Ted Kremenek
committed
#include <sstream>
using namespace clang;
//===----------------------------------------------------------------------===//
// Bug Descriptions.
//===----------------------------------------------------------------------===//
namespace bugdesc {
struct NullDeref {
static const char* getName() { return "Null dereference"; }
static PathDiagnosticPiece* getEndPath(SourceManager& SMgr,
ExplodedNode<ValueState> *N);
};
PathDiagnosticPiece* NullDeref::getEndPath(SourceManager& SMgr,
ExplodedNode<ValueState> *N) {
Expr* E = cast<Expr>(cast<PostStmt>(N->getLocation()).getStmt());
// FIXME: Do better ranges for different kinds of null dereferences.
FullSourceLoc L(E->getLocStart(), SMgr);
PathDiagnosticPiece* P = new PathDiagnosticPiece(L, getName());
P->addRange(E->getSourceRange());
return P;
}
} // end namespace: bugdesc
//===----------------------------------------------------------------------===//
// Utility functions.
//===----------------------------------------------------------------------===//
template <typename ITERATOR>
static inline ExplodedNode<ValueState>* GetNode(ITERATOR I) {
return *I;
}
template <>
static inline ExplodedNode<ValueState>*
GetNode(GRExprEngine::undef_arg_iterator I) {
return I->first;
}
template <typename ITERATOR>
static inline ProgramPoint GetLocation(ITERATOR I) {
return (*I)->getLocation();
}
template <>
static inline ProgramPoint GetLocation(GRExprEngine::undef_arg_iterator I) {
return I->first->getLocation();
}
static inline Stmt* GetStmt(const ProgramPoint& P) {
if (const PostStmt* PS = dyn_cast<PostStmt>(&P)) {
return PS->getStmt();
}
else if (const BlockEdge* BE = dyn_cast<BlockEdge>(&P)) {
return BE->getSrc()->getTerminator();
}
assert (false && "Unsupported ProgramPoint.");
return NULL;
//===----------------------------------------------------------------------===//
// Pathless Warnings
//===----------------------------------------------------------------------===//
template <typename ITERATOR>
Ted Kremenek
committed
static void EmitDiag(Diagnostic& Diag, PathDiagnosticClient* PD,
SourceManager& SrcMgr,
unsigned ErrorDiag, ITERATOR I) {
Stmt* S = GetStmt(GetLocation(I));
SourceRange R = S->getSourceRange();
Diag.Report(PD, FullSourceLoc(S->getLocStart(), SrcMgr), ErrorDiag,
NULL, 0, &R, 1);
}
template <>
Ted Kremenek
committed
static void EmitDiag(Diagnostic& Diag, PathDiagnosticClient* PD,
SourceManager& SrcMgr, unsigned ErrorDiag,
GRExprEngine::undef_arg_iterator I) {
Stmt* S1 = GetStmt(GetLocation(I));
Expr* E2 = cast<Expr>(I->second);
SourceLocation Loc = S1->getLocStart();
SourceRange R = E2->getSourceRange();
Ted Kremenek
committed
Diag.Report(PD, FullSourceLoc(Loc, SrcMgr), ErrorDiag, 0, 0, &R, 1);
template <typename ITERATOR>
static void EmitWarning(Diagnostic& Diag, PathDiagnosticClient* PD,
SourceManager& SrcMgr,
ITERATOR I, ITERATOR E, const char* msg) {
Ted Kremenek
committed
std::ostringstream Out;
std::string Str(msg);
if (!PD) {
Out << "[CHECKER] " << msg;
Str = Out.str();
msg = Str.c_str();
Ted Kremenek
committed
unsigned ErrorDiag = 0;
llvm::SmallPtrSet<void*,10> CachedErrors;
for (; I != E; ++I) {
if (isFirst) {
isFirst = false;
ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning, msg);
}
else {
// HACK: Cache the location of the error. Don't emit the same
// warning for the same error type that occurs at the same program
// location but along a different path.
void* p = GetLocation(I).getRawData();
if (CachedErrors.count(p))
continue;
CachedErrors.insert(p);
}
EmitDiag(Diag, PD, SrcMgr, ErrorDiag, I);
}
}
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
//===----------------------------------------------------------------------===//
// Path warnings.
//===----------------------------------------------------------------------===//
static void GeneratePathDiagnostic(PathDiagnostic& PD,
SourceManager& SMgr,
ExplodedNode<ValueState>* N) {
if (N->pred_empty())
return;
N = *(N->pred_begin());
ProgramPoint P = N->getLocation();
if (const BlockEdge* BE = dyn_cast<BlockEdge>(&P)) {
CFGBlock* Src = BE->getSrc();
CFGBlock* Dst = BE->getDst();
// FIXME: Better handling for switches.
if (Src->succ_size() == 2) {
Stmt* T = Src->getTerminator();
if (!Src)
return;
FullSourceLoc L(T->getLocStart(), SMgr);
if (*(Src->succ_begin()+1) == Dst)
PD.push_front(new PathDiagnosticPiece(L, "Taking false branch."));
else
PD.push_front(new PathDiagnosticPiece(L, "Taking true branch."));
}
}
GeneratePathDiagnostic(PD, SMgr, N);
}
template <typename ITERATOR, typename DESC>
static void Report(PathDiagnosticClient& PDC, SourceManager& SMgr, DESC,
ITERATOR I, ITERATOR E) {
if (I == E)
return;
const char* BugName = DESC::getName();
llvm::SmallPtrSet<void*,10> CachedErrors;
for (; I != E; ++I) {
// HACK: Cache the location of the error. Don't emit the same
// warning for the same error type that occurs at the same program
// location but along a different path.
void* p = GetLocation(I).getRawData();
if (CachedErrors.count(p))
continue;
CachedErrors.insert(p);
// Create the PathDiagnostic.
PathDiagnostic D(BugName);
// Get the end-of-path diagnostic.
D.push_back(DESC::getEndPath(SMgr, GetNode(I)));
// Generate the rest of the diagnostic.
GeneratePathDiagnostic(D, SMgr, GetNode(I));
PDC.HandlePathDiagnostic(D);
}
}
//===----------------------------------------------------------------------===//
// Analysis Driver.
//===----------------------------------------------------------------------===//
namespace clang {
Ted Kremenek
committed
unsigned RunGRSimpleVals(CFG& cfg, Decl& CD, ASTContext& Ctx,
Diagnostic& Diag, PathDiagnosticClient* PD,
bool Visualize, bool TrimGraph) {
Ted Kremenek
committed
GRCoreEngine<GRExprEngine> Eng(cfg, CD, Ctx);
GRExprEngine* CS = &Eng.getCheckerState();
Ted Kremenek
committed
// Set base transfer functions.
GRSimpleVals GRSV;
CS->setTransferFunctions(GRSV);
Ted Kremenek
committed
// Add extra checkers.
llvm::OwningPtr<GRSimpleAPICheck> FoundationCheck(
CreateBasicObjCFoundationChecks(Ctx, &CS->getStateManager()));
Ted Kremenek
committed
CS->AddObjCMessageExprCheck(FoundationCheck.get());
Ted Kremenek
committed
// Execute the worklist algorithm.
Ted Kremenek
committed
Eng.ExecuteWorkList(120000);
SourceManager& SrcMgr = Ctx.getSourceManager();
if (!PD)
EmitWarning(Diag, PD, SrcMgr,
CS->null_derefs_begin(), CS->null_derefs_end(),
"Dereference of NULL pointer.");
else
Report(*PD, SrcMgr, bugdesc::NullDeref(),
CS->null_derefs_begin(), CS->null_derefs_end());
Ted Kremenek
committed
EmitWarning(Diag, PD, SrcMgr,
CS->undef_derefs_begin(),
CS->undef_derefs_end(),
Ted Kremenek
committed
"Dereference of undefined value.");
Ted Kremenek
committed
EmitWarning(Diag, PD, SrcMgr,
CS->undef_branches_begin(),
CS->undef_branches_end(),
"Branch condition evaluates to an uninitialized value.");
Ted Kremenek
committed
EmitWarning(Diag, PD, SrcMgr,
CS->explicit_bad_divides_begin(),
CS->explicit_bad_divides_end(),
Ted Kremenek
committed
"Division by zero/undefined value.");
Ted Kremenek
committed
Ted Kremenek
committed
EmitWarning(Diag, PD, SrcMgr,
CS->undef_results_begin(),
CS->undef_results_end(),
Ted Kremenek
committed
"Result of operation is undefined.");
Ted Kremenek
committed
Ted Kremenek
committed
EmitWarning(Diag, PD, SrcMgr,
CS->bad_calls_begin(),
CS->bad_calls_end(),
Ted Kremenek
committed
"Call using a NULL or undefined function pointer value.");
Ted Kremenek
committed
EmitWarning(Diag, PD, SrcMgr,
CS->undef_arg_begin(),
CS->undef_arg_end(),
"Pass-by-value argument in function is undefined.");
Ted Kremenek
committed
EmitWarning(Diag, PD, SrcMgr,
CS->msg_expr_undef_arg_begin(),
CS->msg_expr_undef_arg_end(),
"Pass-by-value argument in message expression is undefined.");
Ted Kremenek
committed
EmitWarning(Diag, PD, SrcMgr,
CS->undef_receivers_begin(),
CS->undef_receivers_end(),
"Receiver in message expression is an uninitialized value.");
Ted Kremenek
committed
EmitWarning(Diag, PD, SrcMgr,
CS->ret_stackaddr_begin(),
CS->ret_stackaddr_end(),
"Address of stack-allocated variable returned.");
FoundationCheck.get()->ReportResults(Diag);
if (Visualize) CS->ViewGraph(TrimGraph);
#endif
return Eng.getGraph().size();
}
//===----------------------------------------------------------------------===//
// Transfer function for Casts.
//===----------------------------------------------------------------------===//
RVal GRSimpleVals::EvalCast(GRExprEngine& Eng, NonLVal X, QualType T) {
if (!isa<nonlval::ConcreteInt>(X))
return UnknownVal();
BasicValueFactory& BasicVals = Eng.getBasicVals();
llvm::APSInt V = cast<nonlval::ConcreteInt>(X).getValue();
V.setIsUnsigned(T->isUnsignedIntegerType() || T->isPointerType()
|| T->isObjCQualifiedIdType());
V.extOrTrunc(Eng.getContext().getTypeSize(T));
if (T->isPointerType())
return lval::ConcreteInt(BasicVals.getValue(V));
else
return nonlval::ConcreteInt(BasicVals.getValue(V));
}
// Casts.
RVal GRSimpleVals::EvalCast(GRExprEngine& Eng, LVal X, QualType T) {
if (T->isPointerLikeType() || T->isObjCQualifiedIdType())
return X;
assert (T->isIntegerType());
if (!isa<lval::ConcreteInt>(X))
return UnknownVal();
BasicValueFactory& BasicVals = Eng.getBasicVals();
llvm::APSInt V = cast<lval::ConcreteInt>(X).getValue();
V.setIsUnsigned(T->isUnsignedIntegerType() || T->isPointerType());
V.extOrTrunc(Eng.getContext().getTypeSize(T));
return nonlval::ConcreteInt(BasicVals.getValue(V));
Ted Kremenek
committed
}
// Unary operators.
RVal GRSimpleVals::EvalMinus(GRExprEngine& Eng, UnaryOperator* U, NonLVal X){
Ted Kremenek
committed
switch (X.getSubKind()) {
Ted Kremenek
committed
case nonlval::ConcreteIntKind:
return cast<nonlval::ConcreteInt>(X).EvalMinus(Eng.getBasicVals(), U);
Ted Kremenek
committed
default:
return UnknownVal();
RVal GRSimpleVals::EvalComplement(GRExprEngine& Eng, NonLVal X) {
Ted Kremenek
committed
switch (X.getSubKind()) {
Ted Kremenek
committed
case nonlval::ConcreteIntKind:
return cast<nonlval::ConcreteInt>(X).EvalComplement(Eng.getBasicVals());
Ted Kremenek
committed
default:
return UnknownVal();
Ted Kremenek
committed
}
}
// Binary operators.
RVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op,
NonLVal L, NonLVal R) {
BasicValueFactory& BasicVals = Eng.getBasicVals();
while (1) {
switch (L.getSubKind()) {
default:
case nonlval::ConcreteIntKind:
if (isa<nonlval::ConcreteInt>(R)) {
const nonlval::ConcreteInt& L_CI = cast<nonlval::ConcreteInt>(L);
const nonlval::ConcreteInt& R_CI = cast<nonlval::ConcreteInt>(R);
return L_CI.EvalBinOp(BasicVals, Op, R_CI);
}
else {
NonLVal tmp = R;
R = L;
L = tmp;
continue;
}
case nonlval::SymbolValKind: {
if (isa<nonlval::ConcreteInt>(R)) {
const SymIntConstraint& C =
BasicVals.getConstraint(cast<nonlval::SymbolVal>(L).getSymbol(), Op,
cast<nonlval::ConcreteInt>(R).getValue());
return nonlval::SymIntConstraintVal(C);
}
else
return UnknownVal();
}
}
}
}
Ted Kremenek
committed
Ted Kremenek
committed
// Binary Operators (except assignments and comma).
RVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op,
LVal L, LVal R) {
Ted Kremenek
committed
switch (Op) {
Ted Kremenek
committed
default:
return UnknownVal();
case BinaryOperator::EQ:
return EvalEQ(Eng, L, R);
Ted Kremenek
committed
case BinaryOperator::NE:
return EvalNE(Eng, L, R);
Ted Kremenek
committed
}
}
Ted Kremenek
committed
// Pointer arithmetic.
RVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op,
LVal L, NonLVal R) {
return UnknownVal();
Ted Kremenek
committed
}
// Equality operators for LVals.
RVal GRSimpleVals::EvalEQ(GRExprEngine& Eng, LVal L, LVal R) {
BasicValueFactory& BasicVals = Eng.getBasicVals();
switch (L.getSubKind()) {
default:
assert(false && "EQ not implemented for this LVal.");
return UnknownVal();
case lval::ConcreteIntKind:
if (isa<lval::ConcreteInt>(R)) {
bool b = cast<lval::ConcreteInt>(L).getValue() ==
cast<lval::ConcreteInt>(R).getValue();
return NonLVal::MakeIntTruthVal(BasicVals, b);
}
else if (isa<lval::SymbolVal>(R)) {
const SymIntConstraint& C =
BasicVals.getConstraint(cast<lval::SymbolVal>(R).getSymbol(),
BinaryOperator::EQ,
cast<lval::ConcreteInt>(L).getValue());
return nonlval::SymIntConstraintVal(C);
}
break;
case lval::SymbolValKind: {
if (isa<lval::ConcreteInt>(R)) {
const SymIntConstraint& C =
BasicVals.getConstraint(cast<lval::SymbolVal>(L).getSymbol(),
BinaryOperator::EQ,
cast<lval::ConcreteInt>(R).getValue());
return nonlval::SymIntConstraintVal(C);
}
// FIXME: Implement == for lval Symbols. This is mainly useful
// in iterator loops when traversing a buffer, e.g. while(z != zTerm).
// Since this is not useful for many checkers we'll punt on this for
// now.
return UnknownVal();
}
case lval::DeclValKind:
Ted Kremenek
committed
case lval::FuncValKind:
case lval::GotoLabelKind:
return NonLVal::MakeIntTruthVal(BasicVals, L == R);
}
return NonLVal::MakeIntTruthVal(BasicVals, false);
}
RVal GRSimpleVals::EvalNE(GRExprEngine& Eng, LVal L, LVal R) {
BasicValueFactory& BasicVals = Eng.getBasicVals();
switch (L.getSubKind()) {
default:
assert(false && "NE not implemented for this LVal.");
return UnknownVal();
case lval::ConcreteIntKind:
if (isa<lval::ConcreteInt>(R)) {
bool b = cast<lval::ConcreteInt>(L).getValue() !=
cast<lval::ConcreteInt>(R).getValue();
return NonLVal::MakeIntTruthVal(BasicVals, b);
}
else if (isa<lval::SymbolVal>(R)) {
const SymIntConstraint& C =
BasicVals.getConstraint(cast<lval::SymbolVal>(R).getSymbol(),
BinaryOperator::NE,
cast<lval::ConcreteInt>(L).getValue());
return nonlval::SymIntConstraintVal(C);
}
break;
case lval::SymbolValKind: {
if (isa<lval::ConcreteInt>(R)) {
const SymIntConstraint& C =
BasicVals.getConstraint(cast<lval::SymbolVal>(L).getSymbol(),
BinaryOperator::NE,
cast<lval::ConcreteInt>(R).getValue());
return nonlval::SymIntConstraintVal(C);
}
// FIXME: Implement != for lval Symbols. This is mainly useful
// in iterator loops when traversing a buffer, e.g. while(z != zTerm).
// Since this is not useful for many checkers we'll punt on this for
// now.
return UnknownVal();
break;
}
case lval::DeclValKind:
Ted Kremenek
committed
case lval::FuncValKind:
case lval::GotoLabelKind:
return NonLVal::MakeIntTruthVal(BasicVals, L != R);
}
return NonLVal::MakeIntTruthVal(BasicVals, true);
}
//===----------------------------------------------------------------------===//
// Transfer function for Function Calls.
//===----------------------------------------------------------------------===//
void GRSimpleVals::EvalCall(ExplodedNodeSet<ValueState>& Dst,
GRExprEngine& Eng,
GRStmtNodeBuilder<ValueState>& Builder,
CallExpr* CE, LVal L,
ExplodedNode<ValueState>* Pred) {
Ted Kremenek
committed
ValueStateManager& StateMgr = Eng.getStateManager();
ValueState* St = Builder.GetState(Pred);
// Invalidate all arguments passed in by reference (LVals).
for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
I != E; ++I) {
Ted Kremenek
committed
RVal V = StateMgr.GetRVal(St, *I);
if (isa<LVal>(V))
Ted Kremenek
committed
St = StateMgr.SetRVal(St, cast<LVal>(V), UnknownVal());
Ted Kremenek
committed
// Make up a symbol for the return value of this function.
if (CE->getType() != Eng.getContext().VoidTy) {
unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenek
committed
SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
Ted Kremenek
committed
RVal X = CE->getType()->isPointerType()
? cast<RVal>(lval::SymbolVal(Sym))
: cast<RVal>(nonlval::SymbolVal(Sym));
St = StateMgr.SetRVal(St, CE, X, Eng.getCFG().isBlkExpr(CE), false);
}