//=== FlatStore.cpp - Flat region-based store model -------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" #include "llvm/ADT/ImmutableIntervalMap.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; using namespace ento; using llvm::Interval; // The actual store type. typedef llvm::ImmutableIntervalMap BindingVal; typedef llvm::ImmutableMap RegionBindings; namespace { class FlatStoreManager : public StoreManager { RegionBindings::Factory RBFactory; BindingVal::Factory BVFactory; public: FlatStoreManager(GRStateManager &mgr) : StoreManager(mgr), RBFactory(mgr.getAllocator()), BVFactory(mgr.getAllocator()) {} SVal Retrieve(Store store, Loc L, QualType T); StoreRef Bind(Store store, Loc L, SVal val); StoreRef Remove(Store St, Loc L); StoreRef BindCompoundLiteral(Store store, const CompoundLiteralExpr* cl, const LocationContext *LC, SVal v); StoreRef getInitialStore(const LocationContext *InitLoc) { return StoreRef(RBFactory.getEmptyMap().getRoot(), *this); } SubRegionMap *getSubRegionMap(Store store) { return 0; } SVal ArrayToPointer(Loc Array); StoreRef removeDeadBindings(Store store, const StackFrameContext *LCtx, SymbolReaper& SymReaper, llvm::SmallVectorImpl& RegionRoots){ return StoreRef(store, *this); } StoreRef BindDecl(Store store, const VarRegion *VR, SVal initVal); StoreRef BindDeclWithNoInit(Store store, const VarRegion *VR); typedef llvm::DenseSet InvalidatedSymbols; StoreRef invalidateRegions(Store store, const MemRegion * const *I, const MemRegion * const *E, const Expr *Ex, unsigned Count, InvalidatedSymbols &IS, bool invalidateGlobals, InvalidatedRegions *Regions); void print(Store store, llvm::raw_ostream& Out, const char* nl, const char *sep); void iterBindings(Store store, BindingsHandler& f); private: static RegionBindings getRegionBindings(Store store) { return RegionBindings(static_cast(store)); } class RegionInterval { public: const MemRegion *R; Interval I; RegionInterval(const MemRegion *r, int64_t s, int64_t e) : R(r), I(s, e){} }; RegionInterval RegionToInterval(const MemRegion *R); SVal RetrieveRegionWithNoBinding(const MemRegion *R, QualType T); }; } // end anonymous namespace StoreManager *ento::CreateFlatStoreManager(GRStateManager &StMgr) { return new FlatStoreManager(StMgr); } SVal FlatStoreManager::Retrieve(Store store, Loc L, QualType T) { // For access to concrete addresses, return UnknownVal. Checks // for null dereferences (and similar errors) are done by checkers, not // the Store. // FIXME: We can consider lazily symbolicating such memory, but we really // should defer this when we can reason easily about symbolicating arrays // of bytes. if (isa(L)) { return UnknownVal(); } if (!isa(L)) { return UnknownVal(); } const MemRegion *R = cast(L).getRegion(); RegionInterval RI = RegionToInterval(R); // FIXME: FlatStore should handle regions with unknown intervals. if (!RI.R) return UnknownVal(); RegionBindings B = getRegionBindings(store); const BindingVal *BV = B.lookup(RI.R); if (BV) { const SVal *V = BVFactory.lookup(*BV, RI.I); if (V) return *V; else return RetrieveRegionWithNoBinding(R, T); } return RetrieveRegionWithNoBinding(R, T); } SVal FlatStoreManager::RetrieveRegionWithNoBinding(const MemRegion *R, QualType T) { if (R->hasStackNonParametersStorage()) return UndefinedVal(); else return svalBuilder.getRegionValueSymbolVal(cast(R)); } StoreRef FlatStoreManager::Bind(Store store, Loc L, SVal val) { const MemRegion *R = cast(L).getRegion(); RegionBindings B = getRegionBindings(store); const BindingVal *V = B.lookup(R); BindingVal BV = BVFactory.getEmptyMap(); if (V) BV = *V; RegionInterval RI = RegionToInterval(R); // FIXME: FlatStore should handle regions with unknown intervals. if (!RI.R) return StoreRef(B.getRoot(), *this); BV = BVFactory.add(BV, RI.I, val); B = RBFactory.add(B, RI.R, BV); return StoreRef(B.getRoot(), *this); } StoreRef FlatStoreManager::Remove(Store store, Loc L) { return StoreRef(store, *this); } StoreRef FlatStoreManager::BindCompoundLiteral(Store store, const CompoundLiteralExpr* cl, const LocationContext *LC, SVal v) { return StoreRef(store, *this); } SVal FlatStoreManager::ArrayToPointer(Loc Array) { return Array; } StoreRef FlatStoreManager::BindDecl(Store store, const VarRegion *VR, SVal initVal) { return Bind(store, svalBuilder.makeLoc(VR), initVal); } StoreRef FlatStoreManager::BindDeclWithNoInit(Store store, const VarRegion *VR){ return StoreRef(store, *this); } StoreRef FlatStoreManager::invalidateRegions(Store store, const MemRegion * const *I, const MemRegion * const *E, const Expr *Ex, unsigned Count, InvalidatedSymbols &IS, bool invalidateGlobals, InvalidatedRegions *Regions) { assert(false && "Not implemented"); return StoreRef(store, *this); } void FlatStoreManager::print(Store store, llvm::raw_ostream& Out, const char* nl, const char *sep) { } void FlatStoreManager::iterBindings(Store store, BindingsHandler& f) { } FlatStoreManager::RegionInterval FlatStoreManager::RegionToInterval(const MemRegion *R) { switch (R->getKind()) { case MemRegion::VarRegionKind: { QualType T = cast(R)->getValueType(); int64_t Size = Ctx.getTypeSize(T); return RegionInterval(R, 0, Size-1); } case MemRegion::ElementRegionKind: case MemRegion::FieldRegionKind: { RegionOffset Offset = R->getAsOffset(); // We cannot compute offset for all regions, for example, elements // with symbolic offsets. if (!Offset.getRegion()) return RegionInterval(0, 0, 0); int64_t Start = Offset.getOffset(); int64_t Size = Ctx.getTypeSize(cast(R)->getValueType()); return RegionInterval(Offset.getRegion(), Start, Start+Size); } default: llvm_unreachable("Region kind unhandled."); return RegionInterval(0, 0, 0); } }