diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h new file mode 100644 index 0000000000000000000000000000000000000000..555191d99709986e651a32e49f9cc02e003c7f10 --- /dev/null +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h @@ -0,0 +1,57 @@ +//== DynamicTypeMap.h - Dynamic type map ----------------------- -*- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides APIs for tracking dynamic type information. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEMAP_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEMAP_H +#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" +#include "llvm/ADT/ImmutableMap.h" + +namespace clang { +namespace ento { + +/// The GDM component containing the dynamic type info. This is a map from a +/// symbol to its most likely type. +struct DynamicTypeMap {}; +typedef llvm::ImmutableMap<const MemRegion *, DynamicTypeInfo> + DynamicTypeMapImpl; +template <> +struct ProgramStateTrait<DynamicTypeMap> + : public ProgramStatePartialTrait<DynamicTypeMapImpl> { + static void *GDMIndex() { + static int index = 0; + return &index; + } +}; + +/// \brief Get dynamic type information for a region. +DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State, + const MemRegion *Reg); + +/// \brief Set dynamic type information of the region; return the new state. +ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *Reg, + DynamicTypeInfo NewTy); + +/// \brief Set dynamic type information of the region; return the new state. +inline ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, + const MemRegion *Reg, QualType NewTy, + bool CanBeSubClassed = true) { + return setDynamicTypeInfo(State, Reg, + DynamicTypeInfo(NewTy, CanBeSubClassed)); +} + +} // ento +} // clang + +#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEMAP_H diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index ac4e452c0250e51396233dabebc1e3d3fa3ee243..187c836e5784d7b98c5607c0ac617238d021f25b 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -337,20 +337,6 @@ public: bool isTainted(SymbolRef Sym, TaintTagType Kind = TaintTagGeneric) const; bool isTainted(const MemRegion *Reg, TaintTagType Kind=TaintTagGeneric) const; - /// \brief Get dynamic type information for a region. - DynamicTypeInfo getDynamicTypeInfo(const MemRegion *Reg) const; - - /// \brief Set dynamic type information of the region; return the new state. - ProgramStateRef setDynamicTypeInfo(const MemRegion *Reg, - DynamicTypeInfo NewTy) const; - - /// \brief Set dynamic type information of the region; return the new state. - ProgramStateRef setDynamicTypeInfo(const MemRegion *Reg, - QualType NewTy, - bool CanBeSubClassed = true) const { - return setDynamicTypeInfo(Reg, DynamicTypeInfo(NewTy, CanBeSubClassed)); - } - //==---------------------------------------------------------------------==// // Accessing the Generic Data Map (GDM). //==---------------------------------------------------------------------==// diff --git a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index 15137b0d17f580267d15d697f7cdf00d430a9d97..67bdee48acdffa8604acc760ef57b1e0d9675836 100644 --- a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -17,6 +17,7 @@ #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" @@ -27,6 +28,7 @@ namespace { class DynamicTypePropagation: public Checker< check::PreCall, check::PostCall, + check::DeadSymbols, check::PostStmt<ImplicitCastExpr>, check::PostStmt<CXXNewExpr> > { const ObjCObjectType *getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, @@ -40,9 +42,23 @@ public: void checkPostCall(const CallEvent &Call, CheckerContext &C) const; void checkPostStmt(const ImplicitCastExpr *CastE, CheckerContext &C) const; void checkPostStmt(const CXXNewExpr *NewE, CheckerContext &C) const; + void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; }; } +void DynamicTypePropagation::checkDeadSymbols(SymbolReaper &SR, + CheckerContext &C) const { + ProgramStateRef State = C.getState(); + DynamicTypeMapImpl TypeMap = State->get<DynamicTypeMap>(); + for (DynamicTypeMapImpl::iterator I = TypeMap.begin(), E = TypeMap.end(); + I != E; ++I) { + if (!SR.isLiveRegion(I->first)) { + State = State->remove<DynamicTypeMap>(I->first); + } + } + C.addTransition(State); +} + static void recordFixedType(const MemRegion *Region, const CXXMethodDecl *MD, CheckerContext &C) { assert(Region); @@ -52,7 +68,7 @@ static void recordFixedType(const MemRegion *Region, const CXXMethodDecl *MD, QualType Ty = Ctx.getPointerType(Ctx.getRecordType(MD->getParent())); ProgramStateRef State = C.getState(); - State = State->setDynamicTypeInfo(Region, Ty, /*CanBeSubclass=*/false); + State = setDynamicTypeInfo(State, Region, Ty, /*CanBeSubclass=*/false); C.addTransition(State); return; } @@ -131,7 +147,7 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call, return; QualType DynResTy = C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0)); - C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy, false)); + C.addTransition(setDynamicTypeInfo(State, RetReg, DynResTy, false)); break; } case OMF_init: { @@ -140,8 +156,8 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call, const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion(); if (!RecReg) return; - DynamicTypeInfo RecDynType = State->getDynamicTypeInfo(RecReg); - C.addTransition(State->setDynamicTypeInfo(RetReg, RecDynType)); + DynamicTypeInfo RecDynType = getDynamicTypeInfo(State, RecReg); + C.addTransition(setDynamicTypeInfo(State, RetReg, RecDynType)); break; } } @@ -186,7 +202,7 @@ void DynamicTypePropagation::checkPostStmt(const ImplicitCastExpr *CastE, case CK_BitCast: // Only handle ObjCObjects for now. if (const Type *NewTy = getBetterObjCType(CastE, C)) - C.addTransition(C.getState()->setDynamicTypeInfo(ToR, QualType(NewTy,0))); + C.addTransition(setDynamicTypeInfo(C.getState(), ToR, QualType(NewTy,0))); break; } return; @@ -202,8 +218,8 @@ void DynamicTypePropagation::checkPostStmt(const CXXNewExpr *NewE, if (!MR) return; - C.addTransition(C.getState()->setDynamicTypeInfo(MR, NewE->getType(), - /*CanBeSubclass=*/false)); + C.addTransition(setDynamicTypeInfo(C.getState(), MR, NewE->getType(), + /*CanBeSubclass=*/false)); } const ObjCObjectType * @@ -254,7 +270,7 @@ DynamicTypePropagation::getBetterObjCType(const Expr *CastE, CastE->getType()->getAs<ObjCObjectPointerType>(); if (!NewTy) return nullptr; - QualType OldDTy = C.getState()->getDynamicTypeInfo(ToR).getType(); + QualType OldDTy = getDynamicTypeInfo(C.getState(), ToR).getType(); if (OldDTy.isNull()) { return NewTy; } @@ -279,3 +295,4 @@ DynamicTypePropagation::getBetterObjCType(const Expr *CastE, void ento::registerDynamicTypePropagation(CheckerManager &mgr) { mgr.registerChecker<DynamicTypePropagation>(); } + diff --git a/lib/StaticAnalyzer/Core/CMakeLists.txt b/lib/StaticAnalyzer/Core/CMakeLists.txt index 59a6b6fbc5951b4abd161e386d67664dcb971d0a..f0db3812e202e6ad45aefc24ee5318a5c81a46f8 100644 --- a/lib/StaticAnalyzer/Core/CMakeLists.txt +++ b/lib/StaticAnalyzer/Core/CMakeLists.txt @@ -17,6 +17,7 @@ add_clang_library(clangStaticAnalyzerCore CommonBugCategories.cpp ConstraintManager.cpp CoreEngine.cpp + DynamicTypeMap.cpp Environment.cpp ExplodedGraph.cpp ExprEngine.cpp diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp index 78ca2a1b20d15939bc898d90dc5d7106674b4b45..5b6a8258d7adfcb22a07db269de96c611d75e4f8 100644 --- a/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -17,6 +17,7 @@ #include "clang/AST/ParentMap.h" #include "clang/Analysis/ProgramPoint.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/raw_ostream.h" @@ -435,7 +436,7 @@ RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const { return RuntimeDefinition(); // Do we know anything about the type of 'this'? - DynamicTypeInfo DynType = getState()->getDynamicTypeInfo(R); + DynamicTypeInfo DynType = getDynamicTypeInfo(getState(), R); if (!DynType.isValid()) return RuntimeDefinition(); @@ -800,7 +801,7 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const { if (!Receiver) return RuntimeDefinition(); - DynamicTypeInfo DTI = getState()->getDynamicTypeInfo(Receiver); + DynamicTypeInfo DTI = getDynamicTypeInfo(getState(), Receiver); QualType DynType = DTI.getType(); CanBeSubClassed = DTI.canBeASubClass(); ReceiverT = dyn_cast<ObjCObjectPointerType>(DynType); diff --git a/lib/StaticAnalyzer/Core/DynamicTypeMap.cpp b/lib/StaticAnalyzer/Core/DynamicTypeMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fd35b664a9127881571d6d383911a855486a2567 --- /dev/null +++ b/lib/StaticAnalyzer/Core/DynamicTypeMap.cpp @@ -0,0 +1,51 @@ +//==- DynamicTypeMap.cpp - Dynamic Type Info related APIs ----------*- 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 APIs that track and query dynamic type information. This +// information can be used to devirtualize calls during the symbolic exection +// or do type checking. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h" + +namespace clang { +namespace ento { + +DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State, + const MemRegion *Reg) { + Reg = Reg->StripCasts(); + + // Look up the dynamic type in the GDM. + const DynamicTypeInfo *GDMType = State->get<DynamicTypeMap>(Reg); + if (GDMType) + return *GDMType; + + // Otherwise, fall back to what we know about the region. + if (const TypedRegion *TR = dyn_cast<TypedRegion>(Reg)) + return DynamicTypeInfo(TR->getLocationType(), /*CanBeSubclass=*/false); + + if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(Reg)) { + SymbolRef Sym = SR->getSymbol(); + return DynamicTypeInfo(Sym->getType()); + } + + return DynamicTypeInfo(); +} + +ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *Reg, + DynamicTypeInfo NewTy) { + Reg = Reg->StripCasts(); + ProgramStateRef NewState = State->set<DynamicTypeMap>(Reg, NewTy); + assert(NewState); + return NewState; +} + +} // namespace ento +} // namespace clang diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp index 1340104f45e7d3a3c662c502dd53ff7a87eb0867..4f9ad9ebccd9dcc8e698c19adfff17ed4401b47a 100644 --- a/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -752,36 +752,3 @@ bool ProgramState::isTainted(SymbolRef Sym, TaintTagType Kind) const { return Tainted; } -/// The GDM component containing the dynamic type info. This is a map from a -/// symbol to its most likely type. -REGISTER_TRAIT_WITH_PROGRAMSTATE(DynamicTypeMap, - CLANG_ENTO_PROGRAMSTATE_MAP(const MemRegion *, - DynamicTypeInfo)) - -DynamicTypeInfo ProgramState::getDynamicTypeInfo(const MemRegion *Reg) const { - Reg = Reg->StripCasts(); - - // Look up the dynamic type in the GDM. - const DynamicTypeInfo *GDMType = get<DynamicTypeMap>(Reg); - if (GDMType) - return *GDMType; - - // Otherwise, fall back to what we know about the region. - if (const TypedRegion *TR = dyn_cast<TypedRegion>(Reg)) - return DynamicTypeInfo(TR->getLocationType(), /*CanBeSubclass=*/false); - - if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(Reg)) { - SymbolRef Sym = SR->getSymbol(); - return DynamicTypeInfo(Sym->getType()); - } - - return DynamicTypeInfo(); -} - -ProgramStateRef ProgramState::setDynamicTypeInfo(const MemRegion *Reg, - DynamicTypeInfo NewTy) const { - Reg = Reg->StripCasts(); - ProgramStateRef NewState = set<DynamicTypeMap>(Reg, NewTy); - assert(NewState); - return NewState; -}