// 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 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((*I)->getLocation()); Expr* E = cast(L.getStmt()); Diag.Report(FullSourceLoc(E->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(X)) return UnknownVal(); llvm::APSInt V = cast(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(X)) return UnknownVal(); llvm::APSInt V = cast(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(X).EvalMinus(ValMgr, U); default: return cast(UnknownVal()); } } NonLValue GRSimpleVals::EvalComplement(ValueManager& ValMgr, NonLValue X) { switch (X.getSubKind()) { case nonlval::ConcreteIntKind: return cast(X).EvalComplement(ValMgr); default: return cast(UnknownVal()); } } // Binary operators. NonLValue GRSimpleVals::EvalBinaryOp(ValueManager& ValMgr, BinaryOperator::Opcode Op, NonLValue LHS, NonLValue RHS) { if (isa(LHS) || isa(RHS)) return cast(UnknownVal()); if (isa(LHS) || isa(RHS)) return cast(UninitializedVal()); while(1) { switch (LHS.getSubKind()) { default: return cast(UnknownVal()); case nonlval::ConcreteIntKind: if (isa(RHS)) { const nonlval::ConcreteInt& LHS_CI = cast(LHS); const nonlval::ConcreteInt& RHS_CI = cast(RHS); return LHS_CI.EvalBinaryOp(ValMgr, Op, RHS_CI); } else if(isa(RHS)) return cast(UnknownVal()); else { NonLValue tmp = RHS; RHS = LHS; LHS = tmp; continue; } case nonlval::SymbolValKind: { if (isa(RHS)) { const SymIntConstraint& C = ValMgr.getConstraint(cast(LHS).getSymbol(), Op, cast(RHS).getValue()); return nonlval::SymIntConstraintVal(C); } else return cast(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(UnknownVal()); case lval::ConcreteIntKind: if (isa(RHS)) { bool b = cast(LHS).getValue() == cast(RHS).getValue(); return NonLValue::GetIntTruthValue(ValMgr, b); } else if (isa(RHS)) { const SymIntConstraint& C = ValMgr.getConstraint(cast(RHS).getSymbol(), BinaryOperator::EQ, cast(LHS).getValue()); return nonlval::SymIntConstraintVal(C); } break; case lval::SymbolValKind: { if (isa(RHS)) { const SymIntConstraint& C = ValMgr.getConstraint(cast(LHS).getSymbol(), BinaryOperator::EQ, cast(RHS).getValue()); return nonlval::SymIntConstraintVal(C); } assert (!isa(RHS) && "FIXME: Implement unification."); break; } case lval::DeclValKind: if (isa(RHS)) { bool b = cast(LHS) == cast(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(UnknownVal()); case lval::ConcreteIntKind: if (isa(RHS)) { bool b = cast(LHS).getValue() != cast(RHS).getValue(); return NonLValue::GetIntTruthValue(ValMgr, b); } else if (isa(RHS)) { const SymIntConstraint& C = ValMgr.getConstraint(cast(RHS).getSymbol(), BinaryOperator::NE, cast(LHS).getValue()); return nonlval::SymIntConstraintVal(C); } break; case lval::SymbolValKind: { if (isa(RHS)) { const SymIntConstraint& C = ValMgr.getConstraint(cast(LHS).getSymbol(), BinaryOperator::NE, cast(RHS).getValue()); return nonlval::SymIntConstraintVal(C); } assert (!isa(RHS) && "FIXME: Implement sym !=."); break; } case lval::DeclValKind: if (isa(RHS)) { bool b = cast(LHS) == cast(RHS); return NonLValue::GetIntTruthValue(ValMgr, b); } break; } return NonLValue::GetIntTruthValue(ValMgr, true); }