blob: 558a87625efac498e1bee520be9b0d6f1a118683 [file] [log] [blame]
// 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 files defines GRSimpleVals, a sub-class of GRTransferFuncs that
// provides transfer functions for performing simple value tracking with
// limited support for symbolics.
//
//===----------------------------------------------------------------------===//
#include "GRSimpleVals.h"
#include "clang/Basic/Diagnostic.h"
using namespace clang;
namespace clang {
void RunGRSimpleVals(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx,
Diagnostic& Diag, bool Visualize) {
if (Diag.hasErrorOccurred())
return;
GRCoreEngine<GRExprEngine> Engine(cfg, FD, Ctx);
GRExprEngine* CheckerState = &Engine.getCheckerState();
GRSimpleVals GRSV;
CheckerState->setTransferFunctions(GRSV);
// Execute the worklist algorithm.
Engine.ExecuteWorkList();
// Look for explicit-Null dereferences and warn about them.
for (GRExprEngine::null_iterator I=CheckerState->null_begin(),
E=CheckerState->null_end(); I!=E; ++I) {
const PostStmt& L = cast<PostStmt>((*I)->getLocation());
Expr* Exp = cast<Expr>(L.getStmt());
Diag.Report(FullSourceLoc(Exp->getExprLoc(), Ctx.getSourceManager()),
diag::chkr_null_deref_after_check);
}
#ifndef NDEBUG
if (Visualize) CheckerState->ViewGraph();
#endif
}
} // end clang namespace
//===----------------------------------------------------------------------===//
// Transfer function for Casts.
//===----------------------------------------------------------------------===//
RValue GRSimpleVals::EvalCast(ValueManager& ValMgr, NonLValue X,
Expr* CastExpr) {
if (!isa<nonlval::ConcreteInt>(X))
return UnknownVal();
llvm::APSInt V = cast<nonlval::ConcreteInt>(X).getValue();
QualType T = CastExpr->getType();
V.setIsUnsigned(T->isUnsignedIntegerType() || T->isPointerType());
V.extOrTrunc(ValMgr.getContext().getTypeSize(T, CastExpr->getLocStart()));
if (CastExpr->getType()->isPointerType())
return lval::ConcreteInt(ValMgr.getValue(V));
else
return nonlval::ConcreteInt(ValMgr.getValue(V));
}
// Casts.
RValue GRSimpleVals::EvalCast(ValueManager& ValMgr, LValue X, Expr* CastExpr) {
if (CastExpr->getType()->isPointerType())
return X;
assert (CastExpr->getType()->isIntegerType());
if (!isa<lval::ConcreteInt>(X))
return UnknownVal();
llvm::APSInt V = cast<lval::ConcreteInt>(X).getValue();
QualType T = CastExpr->getType();
V.setIsUnsigned(T->isUnsignedIntegerType() || T->isPointerType());
V.extOrTrunc(ValMgr.getContext().getTypeSize(T, CastExpr->getLocStart()));
return nonlval::ConcreteInt(ValMgr.getValue(V));
}
// Unary operators.
NonLValue GRSimpleVals::EvalMinus(ValueManager& ValMgr, UnaryOperator* U,
NonLValue X) {
switch (X.getSubKind()) {
case nonlval::ConcreteIntKind:
return cast<nonlval::ConcreteInt>(X).EvalMinus(ValMgr, U);
default:
return cast<NonLValue>(UnknownVal());
}
}
NonLValue GRSimpleVals::EvalComplement(ValueManager& ValMgr, NonLValue X) {
switch (X.getSubKind()) {
case nonlval::ConcreteIntKind:
return cast<nonlval::ConcreteInt>(X).EvalComplement(ValMgr);
default:
return cast<NonLValue>(UnknownVal());
}
}
// Binary operators.
NonLValue GRSimpleVals::EvalBinaryOp(ValueManager& ValMgr,
BinaryOperator::Opcode Op,
NonLValue LHS, NonLValue RHS) {
if (isa<UnknownVal>(LHS) || isa<UnknownVal>(RHS))
return cast<NonLValue>(UnknownVal());
if (isa<UninitializedVal>(LHS) || isa<UninitializedVal>(RHS))
return cast<NonLValue>(UninitializedVal());
while(1) {
switch (LHS.getSubKind()) {
default:
return cast<NonLValue>(UnknownVal());
case nonlval::ConcreteIntKind:
if (isa<nonlval::ConcreteInt>(RHS)) {
const nonlval::ConcreteInt& LHS_CI = cast<nonlval::ConcreteInt>(LHS);
const nonlval::ConcreteInt& RHS_CI = cast<nonlval::ConcreteInt>(RHS);
return LHS_CI.EvalBinaryOp(ValMgr, Op, RHS_CI);
}
else if(isa<UnknownVal>(RHS))
return cast<NonLValue>(UnknownVal());
else {
NonLValue tmp = RHS;
RHS = LHS;
LHS = tmp;
continue;
}
case nonlval::SymbolValKind: {
if (isa<nonlval::ConcreteInt>(RHS)) {
const SymIntConstraint& C =
ValMgr.getConstraint(cast<nonlval::SymbolVal>(LHS).getSymbol(), Op,
cast<nonlval::ConcreteInt>(RHS).getValue());
return nonlval::SymIntConstraintVal(C);
}
else
return cast<NonLValue>(UnknownVal());
}
}
}
}
// Binary Operators (except assignments and comma).
RValue GRSimpleVals::EvalBinaryOp(ValueManager& ValMgr,
BinaryOperator::Opcode Op,
LValue LHS, LValue RHS) {
switch (Op) {
default:
return UnknownVal();
case BinaryOperator::EQ:
return EvalEQ(ValMgr, LHS, RHS);
case BinaryOperator::NE:
return EvalNE(ValMgr, LHS, RHS);
}
}
// Pointer arithmetic.
LValue GRSimpleVals::EvalBinaryOp(ValueManager& ValMgr,
BinaryOperator::Opcode Op,
LValue LHS, NonLValue RHS) {
return cast<LValue>(UnknownVal());
}
// Equality operators for LValues.
NonLValue GRSimpleVals::EvalEQ(ValueManager& ValMgr, LValue LHS, LValue RHS) {
switch (LHS.getSubKind()) {
default:
assert(false && "EQ not implemented for this LValue.");
return cast<NonLValue>(UnknownVal());
case lval::ConcreteIntKind:
if (isa<lval::ConcreteInt>(RHS)) {
bool b = cast<lval::ConcreteInt>(LHS).getValue() ==
cast<lval::ConcreteInt>(RHS).getValue();
return NonLValue::GetIntTruthValue(ValMgr, b);
}
else if (isa<lval::SymbolVal>(RHS)) {
const SymIntConstraint& C =
ValMgr.getConstraint(cast<lval::SymbolVal>(RHS).getSymbol(),
BinaryOperator::EQ,
cast<lval::ConcreteInt>(LHS).getValue());
return nonlval::SymIntConstraintVal(C);
}
break;
case lval::SymbolValKind: {
if (isa<lval::ConcreteInt>(RHS)) {
const SymIntConstraint& C =
ValMgr.getConstraint(cast<lval::SymbolVal>(LHS).getSymbol(),
BinaryOperator::EQ,
cast<lval::ConcreteInt>(RHS).getValue());
return nonlval::SymIntConstraintVal(C);
}
assert (!isa<lval::SymbolVal>(RHS) && "FIXME: Implement unification.");
break;
}
case lval::DeclValKind:
if (isa<lval::DeclVal>(RHS)) {
bool b = cast<lval::DeclVal>(LHS) == cast<lval::DeclVal>(RHS);
return NonLValue::GetIntTruthValue(ValMgr, b);
}
break;
}
return NonLValue::GetIntTruthValue(ValMgr, false);
}
NonLValue GRSimpleVals::EvalNE(ValueManager& ValMgr, LValue LHS, LValue RHS) {
switch (LHS.getSubKind()) {
default:
assert(false && "NE not implemented for this LValue.");
return cast<NonLValue>(UnknownVal());
case lval::ConcreteIntKind:
if (isa<lval::ConcreteInt>(RHS)) {
bool b = cast<lval::ConcreteInt>(LHS).getValue() !=
cast<lval::ConcreteInt>(RHS).getValue();
return NonLValue::GetIntTruthValue(ValMgr, b);
}
else if (isa<lval::SymbolVal>(RHS)) {
const SymIntConstraint& C =
ValMgr.getConstraint(cast<lval::SymbolVal>(RHS).getSymbol(),
BinaryOperator::NE,
cast<lval::ConcreteInt>(LHS).getValue());
return nonlval::SymIntConstraintVal(C);
}
break;
case lval::SymbolValKind: {
if (isa<lval::ConcreteInt>(RHS)) {
const SymIntConstraint& C =
ValMgr.getConstraint(cast<lval::SymbolVal>(LHS).getSymbol(),
BinaryOperator::NE,
cast<lval::ConcreteInt>(RHS).getValue());
return nonlval::SymIntConstraintVal(C);
}
assert (!isa<lval::SymbolVal>(RHS) && "FIXME: Implement sym !=.");
break;
}
case lval::DeclValKind:
if (isa<lval::DeclVal>(RHS)) {
bool b = cast<lval::DeclVal>(LHS) == cast<lval::DeclVal>(RHS);
return NonLValue::GetIntTruthValue(ValMgr, b);
}
break;
}
return NonLValue::GetIntTruthValue(ValMgr, true);
}