// TODO: once the constraint manager is smart enough to handle non simplified // symbolic expressions remove this function. Note that this can not be used in // the constraint manager as is, since this does not handle overflows. It is // safe to assume, however, that memory offsets will not overflow. static std::pair<NonLoc, nonloc::ConcreteInt> getSimplifiedOffsets(NonLoc offset, nonloc::ConcreteInt extent, SValBuilder &svalBuilder) { Optional<nonloc::SymbolVal> SymVal = offset.getAs<nonloc::SymbolVal>(); if (SymVal && SymVal->isExpression()) { if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(SymVal->getSymbol())) { llvm::APSInt constant = APSIntType(extent.getValue()).convert(SIE->getRHS()); switch (SIE->getOpcode()) { case BO_Mul: // The constant should never be 0 here, since it the result of scaling // based on the size of a type which is never 0. if ((extent.getValue() % constant) != 0) return std::pair<NonLoc, nonloc::ConcreteInt>(offset, extent); else return getSimplifiedOffsets( nonloc::SymbolVal(SIE->getLHS()), svalBuilder.makeIntVal(extent.getValue() / constant), svalBuilder); case BO_Add: return getSimplifiedOffsets( nonloc::SymbolVal(SIE->getLHS()), svalBuilder.makeIntVal(extent.getValue() - constant), svalBuilder); default: break; } } } return std::pair<NonLoc, nonloc::ConcreteInt>(offset, extent); }
static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx, CallEvent::BindingsTy &Bindings, SValBuilder &SVB, const CallEvent &Call, CallEvent::param_iterator I, CallEvent::param_iterator E) { MemRegionManager &MRMgr = SVB.getRegionManager(); // If the function has fewer parameters than the call has arguments, we simply // do not bind any values to them. unsigned NumArgs = Call.getNumArgs(); unsigned Idx = 0; for (; I != E && Idx < NumArgs; ++I, ++Idx) { const ParmVarDecl *ParamDecl = *I; assert(ParamDecl && "Formal parameter has no decl?"); SVal ArgVal = Call.getArgSVal(Idx); if (!ArgVal.isUnknown()) { Loc ParamLoc = SVB.makeLoc(MRMgr.getVarRegion(ParamDecl, CalleeCtx)); Bindings.push_back(std::make_pair(ParamLoc, ArgVal)); } } // FIXME: Variadic arguments are not handled at all right now. }
// Scale a base value by a scaling factor, and return the scaled // value as an SVal. Used by 'computeOffset'. static inline SVal scaleValue(ProgramStateRef state, NonLoc baseVal, CharUnits scaling, SValBuilder &sb) { return sb.evalBinOpNN(state, BO_Mul, baseVal, sb.makeArrayIndex(scaling.getQuantity()), sb.getArrayIndexType()); }
SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder) const { for (;;) { switch (E->getStmtClass()) { case Stmt::AddrLabelExprClass: return svalBuilder.makeLoc(cast<AddrLabelExpr>(E)); case Stmt::ParenExprClass: // ParenExprs are no-ops. E = cast<ParenExpr>(E)->getSubExpr(); continue; case Stmt::CharacterLiteralClass: { const CharacterLiteral* C = cast<CharacterLiteral>(E); return svalBuilder.makeIntVal(C->getValue(), C->getType()); } case Stmt::CXXBoolLiteralExprClass: { const SVal *X = ExprBindings.lookup(E); if (X) return *X; else return svalBuilder.makeIntVal(cast<CXXBoolLiteralExpr>(E)); } case Stmt::IntegerLiteralClass: { // In C++, this expression may have been bound to a temporary object. SVal const *X = ExprBindings.lookup(E); if (X) return *X; else return svalBuilder.makeIntVal(cast<IntegerLiteral>(E)); } case Stmt::ImplicitCastExprClass: case Stmt::CStyleCastExprClass: { // We blast through no-op casts to get the descendant // subexpression that has a value. const CastExpr* C = cast<CastExpr>(E); QualType CT = C->getType(); if (CT->isVoidType()) return UnknownVal(); if (C->getCastKind() == CK_NoOp) { E = C->getSubExpr(); continue; } break; } case Stmt::ExprWithCleanupsClass: E = cast<ExprWithCleanups>(E)->getSubExpr(); continue; case Stmt::CXXBindTemporaryExprClass: E = cast<CXXBindTemporaryExpr>(E)->getSubExpr(); continue; case Stmt::CXXFunctionalCastExprClass: E = cast<CXXFunctionalCastExpr>(E)->getSubExpr(); continue; // Handle all other Stmt* using a lookup. default: break; }; break; } return lookupExpr(E); }
// Add an SVal to another, treating unknown and undefined values as // summing to UnknownVal. Used by 'computeOffset'. static SVal addValue(ProgramStateRef state, SVal x, SVal y, SValBuilder &svalBuilder) { // We treat UnknownVals and UndefinedVals the same here because we // only care about computing offsets. if (x.isUnknownOrUndef() || y.isUnknownOrUndef()) return UnknownVal(); return svalBuilder.evalBinOpNN(state, BO_Add, cast<NonLoc>(x), cast<NonLoc>(y), svalBuilder.getArrayIndexType()); }
DefinedOrUnknownSVal TypedValueRegion::getExtent(SValBuilder &svalBuilder) const { ASTContext &Ctx = svalBuilder.getContext(); QualType T = getDesugaredValueType(Ctx); if (isa<VariableArrayType>(T)) return nonloc::SymbolVal(svalBuilder.getSymbolManager().getExtentSymbol(this)); if (isa<IncompleteArrayType>(T)) return UnknownVal(); CharUnits size = Ctx.getTypeSizeInChars(T); QualType sizeTy = svalBuilder.getArrayIndexType(); return svalBuilder.makeIntVal(size.getQuantity(), sizeTy); }
// When checking for error code, we need to consider the following cases: // 1) noErr / [0] // 2) someErr / [1, inf] // 3) unknown // If noError, returns true iff (1). // If !noError, returns true iff (2). bool MacOSKeychainAPIChecker::definitelyReturnedError(SymbolRef RetSym, ProgramStateRef State, SValBuilder &Builder, bool noError) const { DefinedOrUnknownSVal NoErrVal = Builder.makeIntVal(NoErr, Builder.getSymbolManager().getType(RetSym)); DefinedOrUnknownSVal NoErr = Builder.evalEQ(State, NoErrVal, nonloc::SymbolVal(RetSym)); ProgramStateRef ErrState = State->assume(NoErr, noError); if (ErrState == State) { return true; } return false; }
/// \brief Optionally conjure and return a symbol for offset when processing /// an expression \p Expression. /// If \p Other is a location, conjure a symbol for \p Symbol /// (offset) if it is unknown so that memory arithmetic always /// results in an ElementRegion. /// \p Count The number of times the current basic block was visited. static SVal conjureOffsetSymbolOnLocation( SVal Symbol, SVal Other, Expr* Expression, SValBuilder &svalBuilder, unsigned Count, const LocationContext *LCtx) { QualType Ty = Expression->getType(); if (Other.getAs<Loc>() && Ty->isIntegralOrEnumerationType() && Symbol.isUnknown()) { return svalBuilder.conjureSymbolVal(Expression, LCtx, Ty, Count); } return Symbol; }
SVal nonloc::ConcreteInt::evalBinOp(SValBuilder &svalBuilder, BinaryOperator::Opcode Op, const nonloc::ConcreteInt& R) const { const llvm::APSInt* X = svalBuilder.getBasicValueFactory().evalAPSInt(Op, getValue(), R.getValue()); if (X) return nonloc::ConcreteInt(*X); else return UndefinedVal(); }
DefinedOrUnknownSVal FieldRegion::getExtent(SValBuilder &svalBuilder) const { DefinedOrUnknownSVal Extent = DeclRegion::getExtent(svalBuilder); // A zero-length array at the end of a struct often stands for dynamically- // allocated extra memory. if (Extent.isZeroConstant()) { QualType T = getDesugaredValueType(svalBuilder.getContext()); if (isa<ConstantArrayType>(T)) return UnknownVal(); } return Extent; }
static SVal computeExtentBegin(SValBuilder &svalBuilder, const MemRegion *region) { while (true) switch (region->getKind()) { default: return svalBuilder.makeZeroArrayIndex(); case MemRegion::SymbolicRegionKind: // FIXME: improve this later by tracking symbolic lower bounds // for symbolic regions. return UnknownVal(); case MemRegion::ElementRegionKind: region = cast<SubRegion>(region)->getSuperRegion(); continue; } }
/// Compute a raw byte offset from a base region. Used for array bounds /// checking. RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(ProgramStateRef state, SValBuilder &svalBuilder, SVal location) { const MemRegion *region = location.getAsRegion(); SVal offset = UndefinedVal(); while (region) { switch (region->getKind()) { default: { if (const SubRegion *subReg = dyn_cast<SubRegion>(region)) { offset = getValue(offset, svalBuilder); if (!offset.isUnknownOrUndef()) return RegionRawOffsetV2(subReg, offset); } return RegionRawOffsetV2(); } case MemRegion::ElementRegionKind: { const ElementRegion *elemReg = cast<ElementRegion>(region); SVal index = elemReg->getIndex(); if (!isa<NonLoc>(index)) return RegionRawOffsetV2(); QualType elemType = elemReg->getElementType(); // If the element is an incomplete type, go no further. ASTContext &astContext = svalBuilder.getContext(); if (!IsCompleteType(astContext, elemType)) return RegionRawOffsetV2(); // Update the offset. offset = addValue(state, getValue(offset, svalBuilder), scaleValue(state, cast<NonLoc>(index), astContext.getTypeSizeInChars(elemType), svalBuilder), svalBuilder); if (offset.isUnknownOrUndef()) return RegionRawOffsetV2(); region = elemReg->getSuperRegion(); continue; } } } return RegionRawOffsetV2(); }
SVal Environment::getSVal(const EnvironmentEntry &Entry, SValBuilder& svalBuilder) const { const Stmt *S = Entry.getStmt(); const LocationContext *LCtx = Entry.getLocationContext(); switch (S->getStmtClass()) { case Stmt::CXXBindTemporaryExprClass: case Stmt::ExprWithCleanupsClass: case Stmt::GenericSelectionExprClass: case Stmt::OpaqueValueExprClass: case Stmt::ParenExprClass: case Stmt::SubstNonTypeTemplateParmExprClass: llvm_unreachable("Should have been handled by ignoreTransparentExprs"); case Stmt::AddrLabelExprClass: case Stmt::CharacterLiteralClass: case Stmt::CXXBoolLiteralExprClass: case Stmt::CXXScalarValueInitExprClass: case Stmt::ImplicitValueInitExprClass: case Stmt::IntegerLiteralClass: case Stmt::ObjCBoolLiteralExprClass: case Stmt::CXXNullPtrLiteralExprClass: case Stmt::ObjCStringLiteralClass: case Stmt::StringLiteralClass: case Stmt::TypeTraitExprClass: // Known constants; defer to SValBuilder. return svalBuilder.getConstantVal(cast<Expr>(S)).getValue(); case Stmt::ReturnStmtClass: { const ReturnStmt *RS = cast<ReturnStmt>(S); if (const Expr *RE = RS->getRetValue()) return getSVal(EnvironmentEntry(RE, LCtx), svalBuilder); return UndefinedVal(); } // Handle all other Stmt* using a lookup. default: return lookupExpr(EnvironmentEntry(S, LCtx)); } }
DefinedOrUnknownSVal StringRegion::getExtent(SValBuilder &svalBuilder) const { return svalBuilder.makeIntVal(getStringLiteral()->getByteLength()+1, svalBuilder.getArrayIndexType()); }
DefinedOrUnknownSVal SymbolicRegion::getExtent(SValBuilder &svalBuilder) const { return nonloc::SymbolVal(svalBuilder.getSymbolManager().getExtentSymbol(this)); }
SVal Environment::getSVal(const EnvironmentEntry &Entry, SValBuilder& svalBuilder) const { const Stmt *S = Entry.getStmt(); const LocationContext *LCtx = Entry.getLocationContext(); switch (S->getStmtClass()) { case Stmt::CXXBindTemporaryExprClass: case Stmt::ExprWithCleanupsClass: case Stmt::GenericSelectionExprClass: case Stmt::OpaqueValueExprClass: case Stmt::ParenExprClass: case Stmt::SubstNonTypeTemplateParmExprClass: llvm_unreachable("Should have been handled by ignoreTransparentExprs"); case Stmt::AddrLabelExprClass: return svalBuilder.makeLoc(cast<AddrLabelExpr>(S)); case Stmt::CharacterLiteralClass: { const CharacterLiteral *C = cast<CharacterLiteral>(S); return svalBuilder.makeIntVal(C->getValue(), C->getType()); } case Stmt::CXXBoolLiteralExprClass: return svalBuilder.makeBoolVal(cast<CXXBoolLiteralExpr>(S)); case Stmt::CXXScalarValueInitExprClass: case Stmt::ImplicitValueInitExprClass: { QualType Ty = cast<Expr>(S)->getType(); return svalBuilder.makeZeroVal(Ty); } case Stmt::IntegerLiteralClass: return svalBuilder.makeIntVal(cast<IntegerLiteral>(S)); case Stmt::ObjCBoolLiteralExprClass: return svalBuilder.makeBoolVal(cast<ObjCBoolLiteralExpr>(S)); // For special C0xx nullptr case, make a null pointer SVal. case Stmt::CXXNullPtrLiteralExprClass: return svalBuilder.makeNull(); case Stmt::ObjCStringLiteralClass: { MemRegionManager &MRMgr = svalBuilder.getRegionManager(); const ObjCStringLiteral *SL = cast<ObjCStringLiteral>(S); return svalBuilder.makeLoc(MRMgr.getObjCStringRegion(SL)); } case Stmt::StringLiteralClass: { MemRegionManager &MRMgr = svalBuilder.getRegionManager(); const StringLiteral *SL = cast<StringLiteral>(S); return svalBuilder.makeLoc(MRMgr.getStringRegion(SL)); } case Stmt::ReturnStmtClass: { const ReturnStmt *RS = cast<ReturnStmt>(S); if (const Expr *RE = RS->getRetValue()) return getSVal(EnvironmentEntry(RE, LCtx), svalBuilder); return UndefinedVal(); } // Handle all other Stmt* using a lookup. default: break; } return lookupExpr(EnvironmentEntry(S, LCtx)); }
// Lazily computes a value to be used by 'computeOffset'. If 'val' // is unknown or undefined, we lazily substitute '0'. Otherwise, // return 'val'. static inline SVal getValue(SVal val, SValBuilder &svalBuilder) { return isa<UndefinedVal>(val) ? svalBuilder.makeArrayIndex(0) : val; }
nonloc::ConcreteInt nonloc::ConcreteInt::evalMinus(SValBuilder &svalBuilder) const { return svalBuilder.makeIntVal(-getValue()); }
nonloc::ConcreteInt nonloc::ConcreteInt::evalComplement(SValBuilder &svalBuilder) const { return svalBuilder.makeIntVal(~getValue()); }
SVal Environment::getSVal(const EnvironmentEntry &Entry, SValBuilder& svalBuilder, bool useOnlyDirectBindings) const { if (useOnlyDirectBindings) { // This branch is rarely taken, but can be exercised by // checkers that explicitly bind values to arbitrary // expressions. It is crucial that we do not ignore any // expression here, and do a direct lookup. return lookupExpr(Entry); } const Stmt *E = Entry.getStmt(); const LocationContext *LCtx = Entry.getLocationContext(); for (;;) { if (const Expr *Ex = dyn_cast<Expr>(E)) E = Ex->IgnoreParens(); switch (E->getStmtClass()) { case Stmt::AddrLabelExprClass: return svalBuilder.makeLoc(cast<AddrLabelExpr>(E)); case Stmt::OpaqueValueExprClass: { const OpaqueValueExpr *ope = cast<OpaqueValueExpr>(E); E = ope->getSourceExpr(); continue; } case Stmt::ParenExprClass: case Stmt::GenericSelectionExprClass: llvm_unreachable("ParenExprs and GenericSelectionExprs should " "have been handled by IgnoreParens()"); case Stmt::CharacterLiteralClass: { const CharacterLiteral* C = cast<CharacterLiteral>(E); return svalBuilder.makeIntVal(C->getValue(), C->getType()); } case Stmt::CXXBoolLiteralExprClass: { const SVal *X = ExprBindings.lookup(EnvironmentEntry(E, LCtx)); if (X) return *X; else return svalBuilder.makeBoolVal(cast<CXXBoolLiteralExpr>(E)); } case Stmt::IntegerLiteralClass: { // In C++, this expression may have been bound to a temporary object. SVal const *X = ExprBindings.lookup(EnvironmentEntry(E, LCtx)); if (X) return *X; else return svalBuilder.makeIntVal(cast<IntegerLiteral>(E)); } // For special C0xx nullptr case, make a null pointer SVal. case Stmt::CXXNullPtrLiteralExprClass: return svalBuilder.makeNull(); case Stmt::ExprWithCleanupsClass: E = cast<ExprWithCleanups>(E)->getSubExpr(); continue; case Stmt::CXXBindTemporaryExprClass: E = cast<CXXBindTemporaryExpr>(E)->getSubExpr(); continue; case Stmt::ObjCPropertyRefExprClass: return loc::ObjCPropRef(cast<ObjCPropertyRefExpr>(E)); case Stmt::ReturnStmtClass: { const ReturnStmt *RS = cast<ReturnStmt>(E); if (const Expr *RE = RS->getRetValue()) { E = RE; continue; } return UndefinedVal(); } // Handle all other Stmt* using a lookup. default: break; }; break; } return lookupExpr(EnvironmentEntry(E, LCtx)); }