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"
#include "clang/Basic/SourceManager.h"
Ted Kremenek
committed
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Analysis/PathSensitive/GRState.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/LocalCheckers.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "llvm/Support/Compiler.h"
Ted Kremenek
committed
#include <sstream>
using namespace clang;
//===----------------------------------------------------------------------===//
// Transfer Function creation for External clients.
//===----------------------------------------------------------------------===//
GRTransferFuncs* clang::MakeGRSimpleValsTF() { return new GRSimpleVals(); }
//===----------------------------------------------------------------------===//
// Transfer function for Casts.
//===----------------------------------------------------------------------===//
Zhongxing Xu
committed
SVal GRSimpleVals::EvalCast(GRExprEngine& Eng, NonLoc X, QualType T) {
Zhongxing Xu
committed
if (!isa<nonloc::ConcreteInt>(X))
return UnknownVal();
Zhongxing Xu
committed
bool isLocType = Loc::IsLocType(T);
Ted Kremenek
committed
// Only handle casts from integers to integers.
Zhongxing Xu
committed
if (!isLocType && !T->isIntegerType())
Ted Kremenek
committed
return UnknownVal();
BasicValueFactory& BasicVals = Eng.getBasicVals();
Zhongxing Xu
committed
llvm::APSInt V = cast<nonloc::ConcreteInt>(X).getValue();
V.setIsUnsigned(T->isUnsignedIntegerType() || Loc::IsLocType(T));
V.extOrTrunc(Eng.getContext().getTypeSize(T));
Zhongxing Xu
committed
if (isLocType)
return loc::ConcreteInt(BasicVals.getValue(V));
else
Zhongxing Xu
committed
return nonloc::ConcreteInt(BasicVals.getValue(V));
}
// Casts.
Zhongxing Xu
committed
SVal GRSimpleVals::EvalCast(GRExprEngine& Eng, Loc X, QualType T) {
// Casts from pointers -> pointers, just return the lval.
//
// Casts from pointers -> references, just return the lval. These
// can be introduced by the frontend for corner cases, e.g
// casting from va_list* to __builtin_va_list&.
//
assert (!X.isUnknownOrUndef());
Zhongxing Xu
committed
if (Loc::IsLocType(T) || T->isReferenceType())
return X;
assert (T->isIntegerType());
BasicValueFactory& BasicVals = Eng.getBasicVals();
unsigned BitWidth = Eng.getContext().getTypeSize(T);
if (!isa<loc::ConcreteInt>(X))
return nonloc::LocAsInteger::Make(BasicVals, X, BitWidth);
Zhongxing Xu
committed
llvm::APSInt V = cast<loc::ConcreteInt>(X).getValue();
V.setIsUnsigned(T->isUnsignedIntegerType() || Loc::IsLocType(T));
V.extOrTrunc(BitWidth);
Zhongxing Xu
committed
return nonloc::ConcreteInt(BasicVals.getValue(V));
Ted Kremenek
committed
}
// Unary operators.
Zhongxing Xu
committed
SVal GRSimpleVals::EvalMinus(GRExprEngine& Eng, UnaryOperator* U, NonLoc X){
Ted Kremenek
committed
switch (X.getSubKind()) {
Zhongxing Xu
committed
case nonloc::ConcreteIntKind:
return cast<nonloc::ConcreteInt>(X).EvalMinus(Eng.getBasicVals(), U);
Ted Kremenek
committed
default:
return UnknownVal();
Zhongxing Xu
committed
SVal GRSimpleVals::EvalComplement(GRExprEngine& Eng, NonLoc X) {
Ted Kremenek
committed
switch (X.getSubKind()) {
Zhongxing Xu
committed
case nonloc::ConcreteIntKind:
return cast<nonloc::ConcreteInt>(X).EvalComplement(Eng.getBasicVals());
Ted Kremenek
committed
default:
return UnknownVal();
Ted Kremenek
committed
}
}
// Binary operators.
static unsigned char LNotOpMap[] = {
(unsigned char) BinaryOperator::GE, /* LT => GE */
(unsigned char) BinaryOperator::LE, /* GT => LE */
(unsigned char) BinaryOperator::GT, /* LE => GT */
(unsigned char) BinaryOperator::LT, /* GE => LT */
(unsigned char) BinaryOperator::NE, /* EQ => NE */
(unsigned char) BinaryOperator::EQ /* NE => EQ */
};
SVal GRSimpleVals::DetermEvalBinOpNN(GRExprEngine& Eng,
Ted Kremenek
committed
BinaryOperator::Opcode Op,
Zhongxing Xu
committed
NonLoc L, NonLoc R) {
Ted Kremenek
committed
BasicValueFactory& BasicVals = Eng.getBasicVals();
Ted Kremenek
committed
unsigned subkind = L.getSubKind();
while (1) {
Ted Kremenek
committed
switch (subkind) {
default:
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
case nonloc::LocAsIntegerKind: {
Loc LL = cast<nonloc::LocAsInteger>(L).getLoc();
switch (R.getSubKind()) {
case nonloc::LocAsIntegerKind:
return EvalBinOp(Eng, Op, LL,
cast<nonloc::LocAsInteger>(R).getLoc());
case nonloc::ConcreteIntKind: {
// Transform the integer into a location and compare.
ASTContext& Ctx = Eng.getContext();
llvm::APSInt V = cast<nonloc::ConcreteInt>(R).getValue();
V.setIsUnsigned(true);
V.extOrTrunc(Ctx.getTypeSize(Ctx.VoidPtrTy));
return EvalBinOp(Eng, Op, LL,
loc::ConcreteInt(BasicVals.getValue(V)));
}
default:
switch (Op) {
case BinaryOperator::EQ:
return NonLoc::MakeIntTruthVal(BasicVals, false);
case BinaryOperator::NE:
return NonLoc::MakeIntTruthVal(BasicVals, true);
default:
// This case also handles pointer arithmetic.
return UnknownVal();
}
}
}
Zhongxing Xu
committed
case nonloc::SymIntConstraintValKind: {
Ted Kremenek
committed
// Logical not?
if (!(Op == BinaryOperator::EQ && R.isZeroConstant()))
return UnknownVal();
const SymIntConstraint& C =
Zhongxing Xu
committed
cast<nonloc::SymIntConstraintVal>(L).getConstraint();
BinaryOperator::Opcode Opc = C.getOpcode();
Ted Kremenek
committed
if (Opc < BinaryOperator::LT || Opc > BinaryOperator::NE)
return UnknownVal();
// For comparison operators, translate the constraint by
// changing the opcode.
int idx = (unsigned) Opc - (unsigned) BinaryOperator::LT;
assert (idx >= 0 &&
(unsigned) idx < sizeof(LNotOpMap)/sizeof(unsigned char));
Opc = (BinaryOperator::Opcode) LNotOpMap[idx];
const SymIntConstraint& CNew =
BasicVals.getConstraint(C.getSymbol(), Opc, C.getInt());
Zhongxing Xu
committed
return nonloc::SymIntConstraintVal(CNew);
Zhongxing Xu
committed
case nonloc::ConcreteIntKind:
Zhongxing Xu
committed
if (isa<nonloc::ConcreteInt>(R)) {
const nonloc::ConcreteInt& L_CI = cast<nonloc::ConcreteInt>(L);
const nonloc::ConcreteInt& R_CI = cast<nonloc::ConcreteInt>(R);
return L_CI.EvalBinOp(BasicVals, Op, R_CI);
}
else {
Ted Kremenek
committed
subkind = R.getSubKind();
Zhongxing Xu
committed
NonLoc tmp = R;
R = L;
L = tmp;
Ted Kremenek
committed
// Swap the operators.
switch (Op) {
case BinaryOperator::LT: Op = BinaryOperator::GT; break;
case BinaryOperator::GT: Op = BinaryOperator::LT; break;
case BinaryOperator::LE: Op = BinaryOperator::GE; break;
case BinaryOperator::GE: Op = BinaryOperator::LE; break;
default: break;
}
continue;
}
Zhongxing Xu
committed
case nonloc::SymbolValKind:
if (isa<nonloc::ConcreteInt>(R)) {
const SymIntConstraint& C =
Zhongxing Xu
committed
BasicVals.getConstraint(cast<nonloc::SymbolVal>(L).getSymbol(), Op,
cast<nonloc::ConcreteInt>(R).getValue());
Zhongxing Xu
committed
return nonloc::SymIntConstraintVal(C);
}
else
return UnknownVal();
}
}
}
Ted Kremenek
committed
Ted Kremenek
committed
// Binary Operators (except assignments and comma).
Zhongxing Xu
committed
SVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op,
Loc L, Loc 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.
Zhongxing Xu
committed
SVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op,
Loc L, NonLoc R) {
return UnknownVal();
Ted Kremenek
committed
}
Zhongxing Xu
committed
// Equality operators for Locs.
Zhongxing Xu
committed
SVal GRSimpleVals::EvalEQ(GRExprEngine& Eng, Loc L, Loc R) {
BasicValueFactory& BasicVals = Eng.getBasicVals();
switch (L.getSubKind()) {
default:
Zhongxing Xu
committed
assert(false && "EQ not implemented for this Loc.");
return UnknownVal();
Zhongxing Xu
committed
case loc::ConcreteIntKind:
Zhongxing Xu
committed
if (isa<loc::ConcreteInt>(R)) {
bool b = cast<loc::ConcreteInt>(L).getValue() ==
cast<loc::ConcreteInt>(R).getValue();
Zhongxing Xu
committed
return NonLoc::MakeIntTruthVal(BasicVals, b);
}
Zhongxing Xu
committed
else if (isa<loc::SymbolVal>(R)) {
const SymIntConstraint& C =
Zhongxing Xu
committed
BasicVals.getConstraint(cast<loc::SymbolVal>(R).getSymbol(),
BinaryOperator::EQ,
Zhongxing Xu
committed
cast<loc::ConcreteInt>(L).getValue());
Zhongxing Xu
committed
return nonloc::SymIntConstraintVal(C);
}
break;
Zhongxing Xu
committed
case loc::SymbolValKind: {
Zhongxing Xu
committed
if (isa<loc::ConcreteInt>(R)) {
const SymIntConstraint& C =
Zhongxing Xu
committed
BasicVals.getConstraint(cast<loc::SymbolVal>(L).getSymbol(),
BinaryOperator::EQ,
Zhongxing Xu
committed
cast<loc::ConcreteInt>(R).getValue());
Zhongxing Xu
committed
return nonloc::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();
}
Zhongxing Xu
committed
case loc::MemRegionKind:
case loc::FuncValKind:
case loc::GotoLabelKind:
return NonLoc::MakeIntTruthVal(BasicVals, L == R);
}
Zhongxing Xu
committed
return NonLoc::MakeIntTruthVal(BasicVals, false);
}
Zhongxing Xu
committed
SVal GRSimpleVals::EvalNE(GRExprEngine& Eng, Loc L, Loc R) {
BasicValueFactory& BasicVals = Eng.getBasicVals();
switch (L.getSubKind()) {
default:
Zhongxing Xu
committed
assert(false && "NE not implemented for this Loc.");
return UnknownVal();
Zhongxing Xu
committed
case loc::ConcreteIntKind:
Zhongxing Xu
committed
if (isa<loc::ConcreteInt>(R)) {
bool b = cast<loc::ConcreteInt>(L).getValue() !=
cast<loc::ConcreteInt>(R).getValue();
Zhongxing Xu
committed
return NonLoc::MakeIntTruthVal(BasicVals, b);
}
Zhongxing Xu
committed
else if (isa<loc::SymbolVal>(R)) {
const SymIntConstraint& C =
Zhongxing Xu
committed
BasicVals.getConstraint(cast<loc::SymbolVal>(R).getSymbol(),
BinaryOperator::NE,
Zhongxing Xu
committed
cast<loc::ConcreteInt>(L).getValue());
Zhongxing Xu
committed
return nonloc::SymIntConstraintVal(C);
}
break;
Zhongxing Xu
committed
case loc::SymbolValKind: {
if (isa<loc::ConcreteInt>(R)) {
const SymIntConstraint& C =
Zhongxing Xu
committed
BasicVals.getConstraint(cast<loc::SymbolVal>(L).getSymbol(),
BinaryOperator::NE,
Zhongxing Xu
committed
cast<loc::ConcreteInt>(R).getValue());
Zhongxing Xu
committed
return nonloc::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;
}
Zhongxing Xu
committed
case loc::MemRegionKind:
case loc::FuncValKind:
case loc::GotoLabelKind:
return NonLoc::MakeIntTruthVal(BasicVals, L != R);
}
Zhongxing Xu
committed
return NonLoc::MakeIntTruthVal(BasicVals, true);
}
//===----------------------------------------------------------------------===//
// Transfer function for function calls.
//===----------------------------------------------------------------------===//
void GRSimpleVals::EvalCall(ExplodedNodeSet<GRState>& Dst,
GRExprEngine& Eng,
Zhongxing Xu
committed
CallExpr* CE, SVal L,
GRStateManager& StateMgr = Eng.getStateManager();
const GRState* St = Builder.GetState(Pred);
Zhongxing Xu
committed
// Invalidate all arguments passed in by reference (Locs).
for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
I != E; ++I) {
Zhongxing Xu
committed
SVal V = StateMgr.GetSVal(St, *I);
Zhongxing Xu
committed
if (isa<loc::MemRegionVal>(V))
Zhongxing Xu
committed
else if (isa<nonloc::LocAsInteger>(V))
St = StateMgr.BindLoc(St, cast<nonloc::LocAsInteger>(V).getLoc(),
Ted Kremenek
committed
Ted Kremenek
committed
// Make up a symbol for the return value of this function.
// FIXME: We eventually should handle structs and other compound types
// that are returned by value.
QualType T = CE->getType();
Ted Kremenek
committed
if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) {
Ted Kremenek
committed
unsigned Count = Builder.getCurrentBlockCount();
Ted Kremenek
committed
SymbolRef Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
Ted Kremenek
committed
Zhongxing Xu
committed
SVal X = Loc::IsLocType(CE->getType())
? cast<SVal>(loc::SymbolVal(Sym))
: cast<SVal>(nonloc::SymbolVal(Sym));
Ted Kremenek
committed
St = StateMgr.BindExpr(St, CE, X, Eng.getCFG().isBlkExpr(CE), false);
Ted Kremenek
committed
}
//===----------------------------------------------------------------------===//
// Transfer function for Objective-C message expressions.
//===----------------------------------------------------------------------===//
void GRSimpleVals::EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
GRExprEngine& Eng,
ObjCMessageExpr* ME,
// The basic transfer function logic for message expressions does nothing.
// We just invalidate all arguments passed in by references.
GRStateManager& StateMgr = Eng.getStateManager();
const GRState* St = Builder.GetState(Pred);
for (ObjCMessageExpr::arg_iterator I = ME->arg_begin(), E = ME->arg_end();
I != E; ++I) {
Zhongxing Xu
committed
SVal V = StateMgr.GetSVal(St, *I);
Zhongxing Xu
committed
if (isa<Loc>(V))
}
Builder.MakeNode(Dst, ME, Pred, St);
}