diff --git a/BreakingChanges.md b/BreakingChanges.md index 42faf98f90..597f54a976 100644 --- a/BreakingChanges.md +++ b/BreakingChanges.md @@ -2,6 +2,15 @@ ## development HEAD +- The API of the `TypeHierarchy` interface (and thus the `LLVMTypeHierarchy` and `DIBasedTypeHierarchy` as well) has changed: + - No handling of the super-type relation (only sub-types) + - No VTable handling anymore -- has been out-sourced into `LLVMVFTableProvider` + - minor API changes +- The constructors of the call-graph resolvers have changed. They: + - take the `LLVMProjectIRDB` as pointer-to-const + - take an additional second parameter of type `const LLVMVFTableProvider *` + - not necessarily require a `LLVMTypeHierarchy` anymore +- Some constructors of `LLVMBasedICFG` do not accept a `LLVMTypeHierarchy` pointer anymore - Removed IfdsFieldSensTaintAnalysis as it relies on LLVM's deprecated typed-pointers. ## v2403 diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h index 92e964e142..7cd8e71821 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMBasedICFG.h @@ -21,14 +21,12 @@ #include "phasar/ControlFlow/CallGraphAnalysisType.h" #include "phasar/ControlFlow/ICFGBase.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" +#include "phasar/PhasarLLVM/ControlFlow/LLVMVFTableProvider.h" #include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" #include "phasar/PhasarLLVM/Utils/LLVMBasedContainerConfig.h" -#include "phasar/Utils/MaybeUniquePtr.h" -#include "phasar/Utils/MemoryResource.h" #include "phasar/Utils/Soundness.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instruction.h" @@ -90,17 +88,19 @@ class LLVMBasedICFG : public LLVMBasedCFG, public ICFGBase { bool IncludeGlobals = true); explicit LLVMBasedICFG(LLVMProjectIRDB *IRDB, Resolver &CGResolver, llvm::ArrayRef EntryPoints = {}, - LLVMTypeHierarchy *TH = nullptr, + Soundness S = Soundness::Soundy, + bool IncludeGlobals = true); + explicit LLVMBasedICFG(LLVMProjectIRDB *IRDB, Resolver &CGResolver, + LLVMVFTableProvider VTP, + llvm::ArrayRef EntryPoints = {}, Soundness S = Soundness::Soundy, bool IncludeGlobals = true); /// Creates an ICFG with an already given call-graph - explicit LLVMBasedICFG(CallGraph CG, LLVMProjectIRDB *IRDB, - LLVMTypeHierarchy *TH = nullptr); + explicit LLVMBasedICFG(CallGraph CG, LLVMProjectIRDB *IRDB); explicit LLVMBasedICFG(LLVMProjectIRDB *IRDB, - const nlohmann::json &SerializedCG, - LLVMTypeHierarchy *TH = nullptr); + const nlohmann::json &SerializedCG); // Deleter of LLVMTypeHierarchy may be unknown here... ~LLVMBasedICFG(); @@ -165,13 +165,14 @@ class LLVMBasedICFG : public LLVMBasedCFG, public ICFGBase { void initialize(LLVMProjectIRDB *IRDB, Resolver &CGResolver, llvm::ArrayRef EntryPoints, - LLVMTypeHierarchy *TH, Soundness S, bool IncludeGlobals); + const LLVMVFTableProvider &VTP, Soundness S, + bool IncludeGlobals); // --- CallGraph CG; LLVMProjectIRDB *IRDB = nullptr; - MaybeUniquePtr TH; + LLVMVFTableProvider VTP; }; extern template class ICFGBase; diff --git a/include/phasar/PhasarLLVM/ControlFlow/LLVMVFTableProvider.h b/include/phasar/PhasarLLVM/ControlFlow/LLVMVFTableProvider.h new file mode 100644 index 0000000000..4206070fc1 --- /dev/null +++ b/include/phasar/PhasarLLVM/ControlFlow/LLVMVFTableProvider.h @@ -0,0 +1,40 @@ +/****************************************************************************** + * Copyright (c) 2024 Fabian Schiebel. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of LICENSE.txt. + * + * Contributors: + * Fabian Schiebel and others + *****************************************************************************/ + +#ifndef PHASAR_PHASARLLVM_CONTROLFLOW_LLVMVFTABLEPROVIDER_H +#define PHASAR_PHASARLLVM_CONTROLFLOW_LLVMVFTABLEPROVIDER_H + +#include "phasar/PhasarLLVM/TypeHierarchy/LLVMVFTable.h" + +#include + +namespace llvm { +class Module; +class StructType; +class GlobalVariable; +} // namespace llvm + +namespace psr { +class LLVMProjectIRDB; + +class LLVMVFTableProvider { +public: + explicit LLVMVFTableProvider(const llvm::Module &Mod); + explicit LLVMVFTableProvider(const LLVMProjectIRDB &IRDB); + + [[nodiscard]] bool hasVFTable(const llvm::StructType *Type) const; + [[nodiscard]] const LLVMVFTable * + getVFTableOrNull(const llvm::StructType *Type) const; + +private: + std::unordered_map TypeVFTMap; +}; +} // namespace psr + +#endif // PHASAR_PHASARLLVM_CONTROLFLOW_LLVMVFTABLEPROVIDER_H diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h b/include/phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h index 46c752d3e2..299a600ea9 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h @@ -18,6 +18,7 @@ #define PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_CHARESOLVER_H_ #include "phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h" +#include "phasar/Utils/MaybeUniquePtr.h" namespace llvm { class CallBase; @@ -25,15 +26,20 @@ class Function; } // namespace llvm namespace psr { +class LLVMTypeHierarchy; class CHAResolver : public Resolver { public: - CHAResolver(LLVMProjectIRDB &IRDB, LLVMTypeHierarchy &TH); + CHAResolver(const LLVMProjectIRDB *IRDB, const LLVMVFTableProvider *VTP, + const LLVMTypeHierarchy *TH); ~CHAResolver() override = default; FunctionSetTy resolveVirtualCall(const llvm::CallBase *CallSite) override; [[nodiscard]] std::string str() const override; + +protected: + MaybeUniquePtr TH; }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/DTAResolver.h b/include/phasar/PhasarLLVM/ControlFlow/Resolver/DTAResolver.h index 3cfd888ca3..7b4484f6e1 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/Resolver/DTAResolver.h +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/DTAResolver.h @@ -20,7 +20,7 @@ #include "phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h" #include "phasar/PhasarLLVM/Pointer/TypeGraphs/CachedTypeGraph.h" // To switch the TypeGraph -//#include "phasar/PhasarLLVM/Pointer/TypeGraphs/LazyTypeGraph.h" +// #include "phasar/PhasarLLVM/Pointer/TypeGraphs/LazyTypeGraph.h" #include @@ -55,7 +55,8 @@ class DTAResolver : public CHAResolver { bool heuristicAntiConstructorVtablePos(const llvm::BitCastInst *BitCast); public: - DTAResolver(LLVMProjectIRDB &IRDB, LLVMTypeHierarchy &TH); + DTAResolver(const LLVMProjectIRDB *IRDB, const LLVMVFTableProvider *VTP, + const LLVMTypeHierarchy *TH); ~DTAResolver() override = default; diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/NOResolver.h b/include/phasar/PhasarLLVM/ControlFlow/Resolver/NOResolver.h index 1b23477eea..7fa845080c 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/Resolver/NOResolver.h +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/NOResolver.h @@ -28,7 +28,7 @@ class NOResolver final : public Resolver { const llvm::CallBase *CallSite); public: - NOResolver(LLVMProjectIRDB &IRDB); + NOResolver(const LLVMProjectIRDB *IRDB); ~NOResolver() override = default; diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/OTFResolver.h b/include/phasar/PhasarLLVM/ControlFlow/Resolver/OTFResolver.h index 13c75d8f34..e278cf786f 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/Resolver/OTFResolver.h +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/OTFResolver.h @@ -17,7 +17,7 @@ #ifndef PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_OTFRESOLVER_H_ #define PHASAR_PHASARLLVM_CONTROLFLOW_RESOLVER_OTFRESOLVER_H_ -#include "phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h" +#include "phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h" #include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" #include @@ -42,7 +42,7 @@ class OTFResolver : public Resolver { LLVMAliasInfoRef PT; public: - OTFResolver(LLVMProjectIRDB &IRDB, LLVMTypeHierarchy &TH, + OTFResolver(const LLVMProjectIRDB *IRDB, const LLVMVFTableProvider *VTP, LLVMAliasInfoRef PT); ~OTFResolver() override = default; diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/RTAResolver.h b/include/phasar/PhasarLLVM/ControlFlow/Resolver/RTAResolver.h index 5b67a4c929..6010443f0b 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/Resolver/RTAResolver.h +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/RTAResolver.h @@ -31,7 +31,8 @@ class StructType; namespace psr { class RTAResolver : public CHAResolver { public: - RTAResolver(LLVMProjectIRDB &IRDB, LLVMTypeHierarchy &TH); + RTAResolver(const LLVMProjectIRDB *IRDB, const LLVMVFTableProvider *VTP, + const LLVMTypeHierarchy *TH); ~RTAResolver() override = default; diff --git a/include/phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h b/include/phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h index 73adbd37e8..e8f997f17a 100644 --- a/include/phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h +++ b/include/phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h @@ -34,9 +34,9 @@ class StructType; namespace psr { class LLVMProjectIRDB; +class LLVMVFTableProvider; class LLVMTypeHierarchy; enum class CallGraphAnalysisType; -class LLVMPointsToInfo; [[nodiscard]] std::optional getVFTIndex(const llvm::CallBase *CallSite); @@ -51,10 +51,10 @@ getReceiverType(const llvm::CallBase *CallSite); class Resolver { protected: - LLVMProjectIRDB &IRDB; - LLVMTypeHierarchy *TH; + const LLVMProjectIRDB *IRDB; + const LLVMVFTableProvider *VTP; - Resolver(LLVMProjectIRDB &IRDB); + Resolver(const LLVMProjectIRDB *IRDB); const llvm::Function * getNonPureVirtualVFTEntry(const llvm::StructType *T, unsigned Idx, @@ -63,7 +63,7 @@ class Resolver { public: using FunctionSetTy = llvm::SmallDenseSet; - Resolver(LLVMProjectIRDB &IRDB, LLVMTypeHierarchy &TH); + Resolver(const LLVMProjectIRDB *IRDB, const LLVMVFTableProvider *VTP); virtual ~Resolver() = default; @@ -83,8 +83,9 @@ class Resolver { [[nodiscard]] virtual std::string str() const = 0; static std::unique_ptr create(CallGraphAnalysisType Ty, - LLVMProjectIRDB *IRDB, - LLVMTypeHierarchy *TH, + const LLVMProjectIRDB *IRDB, + const LLVMVFTableProvider *VTP, + const LLVMTypeHierarchy *TH, LLVMAliasInfoRef PT = nullptr); }; } // namespace psr diff --git a/include/phasar/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchy.h b/include/phasar/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchy.h index 0048e2ecf7..dc7df6ea4b 100644 --- a/include/phasar/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchy.h +++ b/include/phasar/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchy.h @@ -38,11 +38,12 @@ class DIBasedTypeHierarchy return TypeToVertex.count(Type); } - [[nodiscard]] bool isSubType(ClassType Type, ClassType SubType) override { + [[nodiscard]] bool isSubType(ClassType Type, + ClassType SubType) const override { return llvm::is_contained(subTypesOf(Type), SubType); } - [[nodiscard]] std::set getSubTypes(ClassType Type) override { + [[nodiscard]] std::set getSubTypes(ClassType Type) const override { const auto &Range = subTypesOf(Type); return {Range.begin(), Range.end()}; } @@ -51,39 +52,27 @@ class DIBasedTypeHierarchy [[nodiscard]] llvm::iterator_range subTypesOf(ClassType Ty) const noexcept; - [[nodiscard]] bool isSuperType(ClassType Type, ClassType SuperType) override; - - /// Not supported yet - [[nodiscard]] std::set getSuperTypes(ClassType Type) override; - [[nodiscard]] ClassType - getType(std::string TypeName) const noexcept override { + getType(llvm::StringRef TypeName) const noexcept override { return NameToType.lookup(TypeName); } - [[nodiscard]] std::set getAllTypes() const override { + [[nodiscard]] std::vector getAllTypes() const override { return {VertexTypes.begin(), VertexTypes.end()}; } [[nodiscard]] const auto &getAllVTables() const noexcept { return VTables; } - [[nodiscard]] std::string getTypeName(ClassType Type) const override { - return Type->getName().str(); + [[nodiscard]] llvm::StringRef getTypeName(ClassType Type) const override { + return Type->getName(); } - [[nodiscard]] bool hasVFTable(ClassType Type) const override; - - [[nodiscard]] const VFTable *getVFTable(ClassType Type) const override { - auto It = TypeToVertex.find(Type); - if (It == TypeToVertex.end()) { - return nullptr; - } - return &VTables[It->second]; + [[nodiscard]] size_t size() const noexcept override { + return VertexTypes.size(); + } + [[nodiscard]] bool empty() const noexcept override { + return VertexTypes.empty(); } - - [[nodiscard]] size_t size() const override { return VertexTypes.size(); } - - [[nodiscard]] bool empty() const override { return VertexTypes.empty(); } void print(llvm::raw_ostream &OS = llvm::outs()) const override; diff --git a/include/phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h b/include/phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h index c5b744e125..98c4dde0b2 100644 --- a/include/phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h +++ b/include/phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h @@ -108,24 +108,8 @@ class LLVMTypeHierarchy // map from clearname to vtable variable std::unordered_map ClearNameTVMap; - static std::string removeStructOrClassPrefix(const llvm::StructType &T); - - static std::string removeStructOrClassPrefix(const std::string &TypeName); - - static std::string removeTypeInfoPrefix(std::string VarName); - - static std::string removeVTablePrefix(std::string VarName); - - static bool isTypeInfo(const std::string &VarName); - - static bool isVTable(const std::string &VarName); - - static bool isStruct(const llvm::StructType &T); - - static bool isStruct(llvm::StringRef TypeName); - std::vector - getSubTypes(const llvm::Module &M, const llvm::StructType &Type); + getSubTypes(const llvm::Module &M, const llvm::StructType &Type) const; std::vector getVirtualFunctions(const llvm::Module &M, const llvm::StructType &Type); @@ -134,12 +118,22 @@ class LLVMTypeHierarchy void buildLLVMTypeHierarchy(const llvm::Module &M); public: + static bool isTypeInfo(llvm::StringRef VarName); + static bool isVTable(llvm::StringRef VarName); + static bool isStruct(const llvm::StructType &T); + static bool isStruct(llvm::StringRef TypeName); + + static std::string removeStructOrClassPrefix(const llvm::StructType &T); + static std::string removeStructOrClassPrefix(llvm::StringRef TypeName); + static std::string removeTypeInfoPrefix(llvm::StringRef VarName); + static std::string removeVTablePrefix(llvm::StringRef VarName); + /** * @brief Creates a LLVMStructTypeHierarchy based on the * given ProjectIRCompiledDB. * @param IRDB ProjectIRCompiledDB object. */ - LLVMTypeHierarchy(LLVMProjectIRDB &IRDB); + LLVMTypeHierarchy(const LLVMProjectIRDB &IRDB); /** * @brief Creates a LLVMStructTypeHierarchy based on the @@ -166,41 +160,30 @@ class LLVMTypeHierarchy [[nodiscard]] inline bool isSubType(const llvm::StructType *Type, - const llvm::StructType *SubType) override { + const llvm::StructType *SubType) const override { auto ReachableTypes = getSubTypes(Type); return ReachableTypes.count(SubType); } std::set - getSubTypes(const llvm::StructType *Type) override; - - [[nodiscard]] inline bool - isSuperType(const llvm::StructType *Type, - const llvm::StructType *SuperType) override { - return isSubType(SuperType, Type); // NOLINT - } - - std::set - getSuperTypes(const llvm::StructType *Type) override; + getSubTypes(const llvm::StructType *Type) const override; [[nodiscard]] const llvm::StructType * - getType(std::string TypeName) const override; + getType(llvm::StringRef TypeName) const override; - [[nodiscard]] std::set getAllTypes() const override; + [[nodiscard]] std::vector + getAllTypes() const override; - [[nodiscard]] std::string + [[nodiscard]] llvm::StringRef getTypeName(const llvm::StructType *Type) const override; - [[nodiscard]] bool hasVFTable(const llvm::StructType *Type) const override; - - [[nodiscard]] const LLVMVFTable * - getVFTable(const llvm::StructType *Type) const override; - - [[nodiscard]] inline size_t size() const override { + [[nodiscard]] size_t size() const noexcept override { return boost::num_vertices(TypeGraph); }; - [[nodiscard]] inline bool empty() const override { return size() == 0; }; + [[nodiscard]] bool empty() const noexcept override { + return boost::num_vertices(TypeGraph) == 0; + }; void print(llvm::raw_ostream &OS = llvm::outs()) const override; diff --git a/include/phasar/TypeHierarchy/TypeHierarchy.h b/include/phasar/TypeHierarchy/TypeHierarchy.h index e3f44e8791..842c46633e 100644 --- a/include/phasar/TypeHierarchy/TypeHierarchy.h +++ b/include/phasar/TypeHierarchy/TypeHierarchy.h @@ -10,14 +10,13 @@ #ifndef PHASAR_TYPEHIERARCHY_TYPEHIERARCHY_H #define PHASAR_TYPEHIERARCHY_TYPEHIERARCHY_H -#include "phasar/TypeHierarchy/VFTable.h" +#include "phasar/Utils/Nullable.h" #include "llvm/Support/raw_ostream.h" -#include "nlohmann/json.hpp" +#include "nlohmann/json_fwd.hpp" #include -#include namespace psr { @@ -25,32 +24,21 @@ template class TypeHierarchy { public: virtual ~TypeHierarchy() = default; - virtual bool hasType(T Type) const = 0; + [[nodiscard]] virtual bool hasType(T Type) const = 0; + [[nodiscard]] virtual bool isSubType(T Type, T SubType) const = 0; - virtual bool isSubType(T Type, T SubType) = 0; + [[nodiscard]] virtual std::set getSubTypes(T Type) const = 0; - virtual std::set getSubTypes(T Type) = 0; + [[nodiscard]] virtual Nullable getType(llvm::StringRef TypeName) const = 0; - virtual bool isSuperType(T Type, T SuperType) = 0; + [[nodiscard]] virtual std::vector getAllTypes() const = 0; - virtual std::set getSuperTypes(T Type) = 0; + [[nodiscard]] virtual llvm::StringRef getTypeName(T Type) const = 0; - [[nodiscard]] virtual T getType(std::string TypeName) const = 0; - - [[nodiscard]] virtual std::set getAllTypes() const = 0; - - [[nodiscard]] virtual std::string getTypeName(T Type) const = 0; - - [[nodiscard]] virtual bool hasVFTable(T Type) const = 0; - - [[nodiscard]] virtual const VFTable *getVFTable(T Type) const = 0; - - [[nodiscard]] virtual size_t size() const = 0; - - [[nodiscard]] virtual bool empty() const = 0; + [[nodiscard]] virtual size_t size() const noexcept = 0; + [[nodiscard]] virtual bool empty() const noexcept = 0; virtual void print(llvm::raw_ostream &OS = llvm::outs()) const = 0; - [[nodiscard]] virtual nlohmann::json getAsJson() const = 0; }; diff --git a/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp b/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp index eadc987db1..f8e56c1828 100644 --- a/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp +++ b/lib/PhasarLLVM/ControlFlow/LLVMBasedICFG.cpp @@ -12,6 +12,7 @@ #include "phasar/ControlFlow/CallGraph.h" #include "phasar/ControlFlow/CallGraphAnalysisType.h" #include "phasar/PhasarLLVM/ControlFlow/LLVMBasedCFG.h" +#include "phasar/PhasarLLVM/ControlFlow/LLVMVFTableProvider.h" #include "phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h" #include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" #include "phasar/PhasarLLVM/Pointer/LLVMAliasInfo.h" @@ -35,7 +36,7 @@ namespace psr { struct LLVMBasedICFG::Builder { LLVMProjectIRDB *IRDB = nullptr; - LLVMTypeHierarchy *TH{}; + const LLVMVFTableProvider *VTP{}; Resolver *Res = nullptr; CallGraphBuilder CGBuilder{}; @@ -233,7 +234,7 @@ bool LLVMBasedICFG::Builder::processFunction(const llvm::Function *F) { } static bool internalIsVirtualFunctionCall(const llvm::Instruction *Inst, - const LLVMTypeHierarchy &TH) { + const LLVMVFTableProvider &VTP) { assert(Inst != nullptr); const auto *CallSite = llvm::dyn_cast(Inst); if (!CallSite) { @@ -244,10 +245,7 @@ static bool internalIsVirtualFunctionCall(const llvm::Instruction *Inst, if (!RecType) { return false; } - if (!TH.hasType(RecType)) { - return false; - } - if (!TH.hasVFTable(RecType)) { + if (!VTP.hasVFTable(RecType)) { return false; } return getVFTIndex(CallSite) >= 0; @@ -274,8 +272,8 @@ bool LLVMBasedICFG::Builder::constructDynamicCall(const llvm::Instruction *CS) { PHASAR_LOG_LEVEL_CAT(DEBUG, "LLVMBasedICFG", " " << llvmIRToString(CS)); // call the resolve routine - assert(TH != nullptr); - auto PossibleTargets = internalIsVirtualFunctionCall(CallSite, *TH) + assert(VTP != nullptr); + auto PossibleTargets = internalIsVirtualFunctionCall(CallSite, *VTP) ? Res->resolveVirtualCall(CallSite) : Res->resolveFunctionPointer(CallSite); @@ -317,9 +315,9 @@ bool LLVMBasedICFG::Builder::constructDynamicCall(const llvm::Instruction *CS) { void LLVMBasedICFG::initialize(LLVMProjectIRDB *IRDB, Resolver &CGResolver, llvm::ArrayRef EntryPoints, - LLVMTypeHierarchy *TH, Soundness S, + const LLVMVFTableProvider &VTP, Soundness S, bool IncludeGlobals) { - Builder B{IRDB, this->TH.get(), &CGResolver}; + Builder B{IRDB, &VTP, &CGResolver}; B.initEntryPoints(EntryPoints); B.initGlobalsAndWorkList(this, IncludeGlobals); @@ -342,13 +340,9 @@ LLVMBasedICFG::LLVMBasedICFG(LLVMProjectIRDB *IRDB, llvm::ArrayRef EntryPoints, LLVMTypeHierarchy *TH, LLVMAliasInfoRef PT, Soundness S, bool IncludeGlobals) - : IRDB(IRDB), TH(TH) { + : IRDB(IRDB), VTP(*IRDB) { assert(IRDB != nullptr); - if (!TH) { - this->TH = std::make_unique(*IRDB); - } - LLVMAliasInfo PTOwn; if (!PT && CGType == CallGraphAnalysisType::OTF) { @@ -356,44 +350,37 @@ LLVMBasedICFG::LLVMBasedICFG(LLVMProjectIRDB *IRDB, PT = PTOwn.asRef(); } - auto CGRes = Resolver::create(CGType, IRDB, this->TH.get(), PT); - initialize(IRDB, *CGRes, EntryPoints, TH, S, IncludeGlobals); + auto CGRes = Resolver::create(CGType, IRDB, &VTP, TH, PT); + initialize(IRDB, *CGRes, EntryPoints, VTP, S, IncludeGlobals); } LLVMBasedICFG::LLVMBasedICFG(LLVMProjectIRDB *IRDB, Resolver &CGResolver, llvm::ArrayRef EntryPoints, - LLVMTypeHierarchy *TH, Soundness S, - bool IncludeGlobals) - : IRDB(IRDB), TH(TH) { + Soundness S, bool IncludeGlobals) + : IRDB(IRDB), VTP(*IRDB) { assert(IRDB != nullptr); - - if (!TH) { - this->TH = std::make_unique(*IRDB); - } - - initialize(IRDB, CGResolver, EntryPoints, TH, S, IncludeGlobals); + initialize(IRDB, CGResolver, EntryPoints, VTP, S, IncludeGlobals); } -LLVMBasedICFG::LLVMBasedICFG(CallGraph CG, LLVMProjectIRDB *IRDB, - LLVMTypeHierarchy *TH) - : CG(std::move(CG)), IRDB(IRDB), TH(TH) { - if (!TH) { - this->TH = std::make_unique(*IRDB); - } +LLVMBasedICFG::LLVMBasedICFG(LLVMProjectIRDB *IRDB, Resolver &CGResolver, + LLVMVFTableProvider VTP, + llvm::ArrayRef EntryPoints, + Soundness S, bool IncludeGlobals) + : IRDB(IRDB), VTP(std::move(VTP)) { + assert(IRDB != nullptr); + initialize(IRDB, CGResolver, EntryPoints, this->VTP, S, IncludeGlobals); } +LLVMBasedICFG::LLVMBasedICFG(CallGraph CG, LLVMProjectIRDB *IRDB) + : CG(std::move(CG)), IRDB(IRDB), VTP(*IRDB) {} + LLVMBasedICFG::LLVMBasedICFG(LLVMProjectIRDB *IRDB, - const nlohmann::json &SerializedCG, - LLVMTypeHierarchy *TH) + const nlohmann::json &SerializedCG) : CG(CallGraph::deserialize( SerializedCG, [IRDB](llvm::StringRef Name) { return IRDB->getFunction(Name); }, [IRDB](size_t Id) { return IRDB->getInstruction(Id); })), - IRDB(IRDB) { - if (!TH) { - this->TH = std::make_unique(*IRDB); - } -} + IRDB(IRDB), VTP(*IRDB) {} LLVMBasedICFG::~LLVMBasedICFG() = default; @@ -425,7 +412,7 @@ bool LLVMBasedICFG::isPhasarGenerated(const llvm::Function &F) noexcept { } [[nodiscard]] bool LLVMBasedICFG::isVirtualFunctionCallImpl(n_t Inst) const { - return internalIsVirtualFunctionCall(Inst, *TH); + return internalIsVirtualFunctionCall(Inst, VTP); } [[nodiscard]] auto LLVMBasedICFG::allNonCallStartNodesImpl() const diff --git a/lib/PhasarLLVM/ControlFlow/LLVMVFTableProvider.cpp b/lib/PhasarLLVM/ControlFlow/LLVMVFTableProvider.cpp new file mode 100644 index 0000000000..b34384bd22 --- /dev/null +++ b/lib/PhasarLLVM/ControlFlow/LLVMVFTableProvider.cpp @@ -0,0 +1,65 @@ +#include "phasar/PhasarLLVM/ControlFlow/LLVMVFTableProvider.h" + +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" +#include "phasar/PhasarLLVM/TypeHierarchy/LLVMVFTable.h" +#include "phasar/Utils/Logger.h" + +#include "llvm/Demangle/Demangle.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Module.h" + +using namespace psr; + +static std::vector getVirtualFunctions( + const llvm::StringMap &ClearNameTVMap, + const llvm::StructType &Type) { + auto ClearName = LLVMTypeHierarchy::removeStructOrClassPrefix(Type.getName()); + + auto It = ClearNameTVMap.find(ClearName); + + if (It != ClearNameTVMap.end()) { + if (const auto *TI = llvm::dyn_cast(It->second)) { + if (!TI->hasInitializer()) { + PHASAR_LOG_LEVEL_CAT(DEBUG, "LLVMTypeHierarchy", + ClearName << " does not have initializer"); + return {}; + } + if (const auto *I = + llvm::dyn_cast(TI->getInitializer())) { + return LLVMVFTable::getVFVectorFromIRVTable(*I); + } + } + } + return {}; +} + +LLVMVFTableProvider::LLVMVFTableProvider(const llvm::Module &Mod) { + auto StructTypes = Mod.getIdentifiedStructTypes(); + llvm::StringMap ClearNameTVMap; + + for (const auto &Glob : Mod.globals()) { + if (LLVMTypeHierarchy::isVTable(Glob.getName())) { + auto Demang = llvm::demangle(Glob.getName().str()); + auto ClearName = LLVMTypeHierarchy::removeVTablePrefix(Demang); + ClearNameTVMap.try_emplace(ClearName, &Glob); + } + } + + for (const auto *Ty : StructTypes) { + TypeVFTMap.try_emplace(Ty, getVirtualFunctions(ClearNameTVMap, *Ty)); + } +} + +LLVMVFTableProvider::LLVMVFTableProvider(const LLVMProjectIRDB &IRDB) + : LLVMVFTableProvider(*IRDB.getModule()) {} + +bool LLVMVFTableProvider::hasVFTable(const llvm::StructType *Type) const { + return TypeVFTMap.count(Type); +} + +const LLVMVFTable * +LLVMVFTableProvider::getVFTableOrNull(const llvm::StructType *Type) const { + auto It = TypeVFTMap.find(Type); + return It != TypeVFTMap.end() ? &It->second : nullptr; +} diff --git a/lib/PhasarLLVM/ControlFlow/Resolver/CHAResolver.cpp b/lib/PhasarLLVM/ControlFlow/Resolver/CHAResolver.cpp index 2e841321be..6b2c144a58 100644 --- a/lib/PhasarLLVM/ControlFlow/Resolver/CHAResolver.cpp +++ b/lib/PhasarLLVM/ControlFlow/Resolver/CHAResolver.cpp @@ -26,11 +26,19 @@ #include "llvm/IR/Instruction.h" #include "llvm/IR/Module.h" +#include + using namespace std; using namespace psr; -CHAResolver::CHAResolver(LLVMProjectIRDB &IRDB, LLVMTypeHierarchy &TH) - : Resolver(IRDB, TH) {} +CHAResolver::CHAResolver(const LLVMProjectIRDB *IRDB, + const LLVMVFTableProvider *VTP, + const LLVMTypeHierarchy *TH) + : Resolver(IRDB, VTP), TH(TH) { + if (!TH) { + this->TH = std::make_unique(*IRDB); + } +} auto CHAResolver::resolveVirtualCall(const llvm::CallBase *CallSite) -> FunctionSetTy { @@ -58,7 +66,7 @@ auto CHAResolver::resolveVirtualCall(const llvm::CallBase *CallSite) const auto *ReceiverTy = getReceiverType(CallSite); // also insert all possible subtypes vtable entries - auto FallbackTys = Resolver::TH->getSubTypes(ReceiverTy); + auto FallbackTys = TH->getSubTypes(ReceiverTy); FunctionSetTy PossibleCallees; diff --git a/lib/PhasarLLVM/ControlFlow/Resolver/DTAResolver.cpp b/lib/PhasarLLVM/ControlFlow/Resolver/DTAResolver.cpp index b143d10ea1..eed1094223 100644 --- a/lib/PhasarLLVM/ControlFlow/Resolver/DTAResolver.cpp +++ b/lib/PhasarLLVM/ControlFlow/Resolver/DTAResolver.cpp @@ -16,6 +16,7 @@ #include "phasar/PhasarLLVM/ControlFlow/Resolver/DTAResolver.h" +#include "phasar/PhasarLLVM/ControlFlow/LLVMVFTableProvider.h" #include "phasar/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.h" #include "phasar/PhasarLLVM/Utils/LLVMShorthands.h" #include "phasar/Utils/Logger.h" @@ -34,8 +35,10 @@ using namespace psr; -DTAResolver::DTAResolver(LLVMProjectIRDB &IRDB, LLVMTypeHierarchy &TH) - : CHAResolver(IRDB, TH) {} +DTAResolver::DTAResolver(const LLVMProjectIRDB *IRDB, + const LLVMVFTableProvider *VTP, + const LLVMTypeHierarchy *TH) + : CHAResolver(IRDB, VTP, TH) {} bool DTAResolver::heuristicAntiConstructorThisType( const llvm::BitCastInst *BitCast) { @@ -80,8 +83,7 @@ bool DTAResolver::heuristicAntiConstructorVtablePos( // If it doesn't contain vtable, there is no reason to call this class in // the DTA graph, so no need to add it if (StructTy->isStructTy()) { - if (Resolver::TH->hasVFTable( - llvm::dyn_cast(StructTy))) { + if (VTP->hasVFTable(llvm::dyn_cast(StructTy))) { return false; } } diff --git a/lib/PhasarLLVM/ControlFlow/Resolver/NOResolver.cpp b/lib/PhasarLLVM/ControlFlow/Resolver/NOResolver.cpp index 2f22b1c2e7..80b99a71a8 100644 --- a/lib/PhasarLLVM/ControlFlow/Resolver/NOResolver.cpp +++ b/lib/PhasarLLVM/ControlFlow/Resolver/NOResolver.cpp @@ -22,7 +22,7 @@ using namespace psr; namespace psr { -NOResolver::NOResolver(LLVMProjectIRDB &IRDB) : Resolver(IRDB) {} +NOResolver::NOResolver(const LLVMProjectIRDB *IRDB) : Resolver(IRDB) {} void NOResolver::preCall(const llvm::Instruction *Inst) {} diff --git a/lib/PhasarLLVM/ControlFlow/Resolver/OTFResolver.cpp b/lib/PhasarLLVM/ControlFlow/Resolver/OTFResolver.cpp index 261ea90ed9..c1f783d54b 100644 --- a/lib/PhasarLLVM/ControlFlow/Resolver/OTFResolver.cpp +++ b/lib/PhasarLLVM/ControlFlow/Resolver/OTFResolver.cpp @@ -30,9 +30,9 @@ using namespace psr; -OTFResolver::OTFResolver(LLVMProjectIRDB &IRDB, LLVMTypeHierarchy &TH, - LLVMAliasInfoRef PT) - : Resolver(IRDB, TH), PT(PT) {} +OTFResolver::OTFResolver(const LLVMProjectIRDB *IRDB, + const LLVMVFTableProvider *VTP, LLVMAliasInfoRef PT) + : Resolver(IRDB, VTP), PT(PT) {} void OTFResolver::preCall(const llvm::Instruction *Inst) {} diff --git a/lib/PhasarLLVM/ControlFlow/Resolver/RTAResolver.cpp b/lib/PhasarLLVM/ControlFlow/Resolver/RTAResolver.cpp index 817f9a209c..27ec5c5a1a 100644 --- a/lib/PhasarLLVM/ControlFlow/Resolver/RTAResolver.cpp +++ b/lib/PhasarLLVM/ControlFlow/Resolver/RTAResolver.cpp @@ -35,8 +35,10 @@ using namespace std; using namespace psr; -RTAResolver::RTAResolver(LLVMProjectIRDB &IRDB, LLVMTypeHierarchy &TH) - : CHAResolver(IRDB, TH) { +RTAResolver::RTAResolver(const LLVMProjectIRDB *IRDB, + const LLVMVFTableProvider *VTP, + const LLVMTypeHierarchy *TH) + : CHAResolver(IRDB, VTP, TH) { resolveAllocatedStructTypes(); } @@ -65,7 +67,7 @@ auto RTAResolver::resolveVirtualCall(const llvm::CallBase *CallSite) const auto *ReceiverType = getReceiverType(CallSite); // also insert all possible subtypes vtable entries - auto ReachableTypes = Resolver::TH->getSubTypes(ReceiverType); + auto ReachableTypes = TH->getSubTypes(ReceiverType); // also insert all possible subtypes vtable entries @@ -100,7 +102,7 @@ void RTAResolver::resolveAllocatedStructTypes() { llvm::DenseSet AllocatedStructTypes; - for (const auto *Fun : IRDB.getAllFunctions()) { + for (const auto *Fun : IRDB->getAllFunctions()) { for (const auto &Inst : llvm::instructions(Fun)) { if (const auto *Alloca = llvm::dyn_cast(&Inst)) { if (const auto *StructTy = @@ -150,5 +152,4 @@ void RTAResolver::resolveAllocatedStructTypes() { this->AllocatedStructTypes.insert(this->AllocatedStructTypes.end(), AllocatedStructTypes.begin(), AllocatedStructTypes.end()); - /// TODO: implement } diff --git a/lib/PhasarLLVM/ControlFlow/Resolver/Resolver.cpp b/lib/PhasarLLVM/ControlFlow/Resolver/Resolver.cpp index 0beb6d1747..745a4e8667 100644 --- a/lib/PhasarLLVM/ControlFlow/Resolver/Resolver.cpp +++ b/lib/PhasarLLVM/ControlFlow/Resolver/Resolver.cpp @@ -17,6 +17,7 @@ #include "phasar/PhasarLLVM/ControlFlow/Resolver/Resolver.h" #include "phasar/ControlFlow/CallGraphAnalysisType.h" +#include "phasar/PhasarLLVM/ControlFlow/LLVMVFTableProvider.h" #include "phasar/PhasarLLVM/ControlFlow/Resolver/CHAResolver.h" #include "phasar/PhasarLLVM/ControlFlow/Resolver/DTAResolver.h" #include "phasar/PhasarLLVM/ControlFlow/Resolver/NOResolver.h" @@ -36,7 +37,6 @@ #include #include -#include std::optional psr::getVFTIndex(const llvm::CallBase *CallSite) { // deal with a virtual member function @@ -110,16 +110,21 @@ bool psr::isConsistentCall(const llvm::CallBase *CallSite, namespace psr { -Resolver::Resolver(LLVMProjectIRDB &IRDB) : IRDB(IRDB), TH(nullptr) {} +Resolver::Resolver(const LLVMProjectIRDB *IRDB) : IRDB(IRDB), VTP(nullptr) { + assert(IRDB != nullptr); +} -Resolver::Resolver(LLVMProjectIRDB &IRDB, LLVMTypeHierarchy &TH) - : IRDB(IRDB), TH(&TH) {} +Resolver::Resolver(const LLVMProjectIRDB *IRDB, const LLVMVFTableProvider *VTP) + : IRDB(IRDB), VTP(VTP) {} const llvm::Function * Resolver::getNonPureVirtualVFTEntry(const llvm::StructType *T, unsigned Idx, const llvm::CallBase *CallSite) { - if (TH && TH->hasVFTable(T)) { - const auto *Target = TH->getVFTable(T)->getFunction(Idx); + if (!VTP) { + return nullptr; + } + if (const auto *VT = VTP->getVFTableOrNull(T)) { + const auto *Target = VT->getFunction(Idx); if (Target && Target->getName() != LLVMTypeHierarchy::PureVirtualCallName && isConsistentCall(CallSite, Target)) { return Target; @@ -144,7 +149,7 @@ auto Resolver::resolveFunctionPointer(const llvm::CallBase *CallSite) "Call function pointer: " << llvmIRToString(CallSite)); FunctionSetTy CalleeTargets; - for (const auto *F : IRDB.getAllFunctions()) { + for (const auto *F : IRDB->getAllFunctions()) { if (F->hasAddressTaken() && isConsistentCall(CallSite, F)) { CalleeTargets.insert(F); } @@ -156,30 +161,31 @@ auto Resolver::resolveFunctionPointer(const llvm::CallBase *CallSite) void Resolver::otherInst(const llvm::Instruction *Inst) {} std::unique_ptr Resolver::create(CallGraphAnalysisType Ty, - LLVMProjectIRDB *IRDB, - LLVMTypeHierarchy *TH, + const LLVMProjectIRDB *IRDB, + const LLVMVFTableProvider *VTP, + const LLVMTypeHierarchy *TH, LLVMAliasInfoRef PT) { assert(IRDB != nullptr); + assert(VTP != nullptr); switch (Ty) { case CallGraphAnalysisType::NORESOLVE: - return std::make_unique(*IRDB); + return std::make_unique(IRDB); case CallGraphAnalysisType::CHA: assert(TH != nullptr); - return std::make_unique(*IRDB, *TH); + return std::make_unique(IRDB, VTP, TH); case CallGraphAnalysisType::RTA: assert(TH != nullptr); - return std::make_unique(*IRDB, *TH); + return std::make_unique(IRDB, VTP, TH); case CallGraphAnalysisType::DTA: assert(TH != nullptr); - return std::make_unique(*IRDB, *TH); + return std::make_unique(IRDB, VTP, TH); case CallGraphAnalysisType::VTA: llvm::report_fatal_error( "The VTA callgraph algorithm is not implemented yet"); case CallGraphAnalysisType::OTF: - assert(TH != nullptr); assert(PT); - return std::make_unique(*IRDB, *TH, PT); + return std::make_unique(IRDB, VTP, PT); case CallGraphAnalysisType::Invalid: llvm::report_fatal_error("Invalid callgraph algorithm specified"); } diff --git a/lib/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchy.cpp b/lib/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchy.cpp index e84c09f171..fd01a07595 100644 --- a/lib/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchy.cpp +++ b/lib/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchy.cpp @@ -207,22 +207,6 @@ auto DIBasedTypeHierarchy::subTypesOf(ClassType Ty) const noexcept return subTypesOf(It->second); } -[[nodiscard]] bool DIBasedTypeHierarchy::isSuperType(ClassType Type, - ClassType SuperType) { - return isSubType(SuperType, Type); // NOLINT -} - -[[nodiscard]] auto DIBasedTypeHierarchy::getSuperTypes(ClassType /*Type*/) - -> std::set { - // TODO: implement (low priority) - llvm::report_fatal_error("Not implemented"); -} - -[[nodiscard]] bool DIBasedTypeHierarchy::hasVFTable(ClassType Type) const { - const auto *StructTy = llvm::dyn_cast(Type); - return StructTy && StructTy->getVTableHolder(); -} - void DIBasedTypeHierarchy::print(llvm::raw_ostream &OS) const { { OS << "Type Hierarchy:\n"; diff --git a/lib/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.cpp b/lib/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.cpp index bc2e32534c..2fe8ac9547 100644 --- a/lib/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.cpp +++ b/lib/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchy.cpp @@ -24,6 +24,7 @@ #include "phasar/Utils/PAMMMacros.h" #include "phasar/Utils/Utilities.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Demangle/Demangle.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" @@ -68,7 +69,7 @@ std::string LLVMTypeHierarchy::VertexProperties::getTypeName() const { return Type->getStructName().str(); } -LLVMTypeHierarchy::LLVMTypeHierarchy(LLVMProjectIRDB &IRDB) { +LLVMTypeHierarchy::LLVMTypeHierarchy(const LLVMProjectIRDB &IRDB) { PHASAR_LOG_LEVEL(INFO, "Construct type hierarchy"); buildLLVMTypeHierarchy(*IRDB.getModule()); } @@ -85,46 +86,51 @@ LLVMTypeHierarchy::removeStructOrClassPrefix(const llvm::StructType &T) { } std::string -LLVMTypeHierarchy::removeStructOrClassPrefix(const std::string &TypeName) { - llvm::StringRef SR(TypeName); - if (SR.startswith(StructPrefix)) { - return SR.drop_front(StructPrefix.size()).str(); +LLVMTypeHierarchy::removeStructOrClassPrefix(llvm::StringRef TypeName) { + if (TypeName.startswith(StructPrefix)) { + return TypeName.drop_front(StructPrefix.size()).str(); } - if (SR.startswith(ClassPrefix)) { - return SR.drop_front(ClassPrefix.size()).str(); + if (TypeName.startswith(ClassPrefix)) { + return TypeName.drop_front(ClassPrefix.size()).str(); } - return TypeName; + return TypeName.str(); } -std::string LLVMTypeHierarchy::removeTypeInfoPrefix(std::string VarName) { - llvm::StringRef SR(VarName); - if (SR.startswith(TypeInfoPrefixDemang)) { - return SR.drop_front(TypeInfoPrefixDemang.size()).str(); +std::string LLVMTypeHierarchy::removeTypeInfoPrefix(llvm::StringRef VarName) { + if (VarName.startswith(TypeInfoPrefixDemang)) { + return VarName.drop_front(TypeInfoPrefixDemang.size()).str(); } - if (SR.startswith(TypeInfoPrefix)) { - return SR.drop_front(TypeInfoPrefix.size()).str(); + if (VarName.startswith(TypeInfoPrefix)) { + return VarName.drop_front(TypeInfoPrefix.size()).str(); } - return VarName; + return VarName.str(); } -std::string LLVMTypeHierarchy::removeVTablePrefix(std::string VarName) { - llvm::StringRef SR(VarName); - if (SR.startswith(VTablePrefixDemang)) { - return SR.drop_front(VTablePrefixDemang.size()).str(); +std::string LLVMTypeHierarchy::removeVTablePrefix(llvm::StringRef VarName) { + if (VarName.startswith(VTablePrefixDemang)) { + return VarName.drop_front(VTablePrefixDemang.size()).str(); } - if (SR.startswith(VTablePrefix)) { - return SR.drop_front(VTablePrefix.size()).str(); + if (VarName.startswith(VTablePrefix)) { + return VarName.drop_front(VTablePrefix.size()).str(); } - return VarName; + return VarName.str(); } -bool LLVMTypeHierarchy::isTypeInfo(const std::string &VarName) { - auto Demang = llvm::demangle(VarName); +bool LLVMTypeHierarchy::isTypeInfo(llvm::StringRef VarName) { + if (VarName.startswith("_ZTI")) { + return true; + } + // In LLVM 16 demangle() takes a StringRef + auto Demang = llvm::demangle(VarName.str()); return llvm::StringRef(Demang).startswith(TypeInfoPrefixDemang); } -bool LLVMTypeHierarchy::isVTable(const std::string &VarName) { - auto Demang = llvm::demangle(VarName); +bool LLVMTypeHierarchy::isVTable(llvm::StringRef VarName) { + if (VarName.startswith("_ZTV")) { + return true; + } + // In LLVM 16 demangle() takes a StringRef + auto Demang = llvm::demangle(VarName.str()); return llvm::StringRef(Demang).startswith(VTablePrefixDemang); } @@ -152,11 +158,12 @@ void LLVMTypeHierarchy::buildLLVMTypeHierarchy(const llvm::Module &M) { std::vector LLVMTypeHierarchy::getSubTypes(const llvm::Module & /*M*/, - const llvm::StructType &Type) { + const llvm::StructType &Type) const { // find corresponding type info variable std::vector SubTypes; std::string ClearName = removeStructOrClassPrefix(Type); - if (const auto *TI = ClearNameTIMap[ClearName]) { + if (auto It = ClearNameTIMap.find(ClearName); It != ClearNameTIMap.end()) { + const auto *TI = It->second; if (!TI->hasInitializer()) { PHASAR_LOG_LEVEL_CAT(DEBUG, "LLVMTypeHierarchy", ClearName << " does not have initializer"); @@ -172,8 +179,9 @@ LLVMTypeHierarchy::getSubTypes(const llvm::Module & /*M*/, if (Name.find(TypeInfoPrefix) != llvm::StringRef::npos) { auto ClearName = removeTypeInfoPrefix(llvm::demangle(Name.str())); - if (const auto *Type = ClearNameTypeMap[ClearName]) { - SubTypes.push_back(Type); + if (auto TyIt = ClearNameTypeMap.find(ClearName); + TyIt != ClearNameTypeMap.end()) { + SubTypes.push_back(TyIt->second); } } } @@ -188,7 +196,7 @@ LLVMTypeHierarchy::getSubTypes(const llvm::Module & /*M*/, std::vector LLVMTypeHierarchy::getVirtualFunctions(const llvm::Module &M, const llvm::StructType &Type) { - auto ClearName = removeStructOrClassPrefix(Type.getName().str()); + auto ClearName = removeStructOrClassPrefix(Type.getName()); std::vector VFS; if (const auto *TV = ClearNameTVMap[ClearName]) { if (const auto *TI = llvm::dyn_cast(TV)) { @@ -218,12 +226,12 @@ void LLVMTypeHierarchy::constructHierarchy(const llvm::Module &M) { } for (const auto &Global : M.globals()) { if (Global.hasName()) { - if (isTypeInfo(Global.getName().str())) { + if (isTypeInfo(Global.getName())) { auto Demang = llvm::demangle(Global.getName().str()); auto ClearName = removeTypeInfoPrefix(Demang); ClearNameTIMap[ClearName] = &Global; } - if (isVTable(Global.getName().str())) { + if (isVTable(Global.getName())) { auto Demang = llvm::demangle(Global.getName().str()); auto ClearName = removeVTablePrefix(Demang); ClearNameTVMap[ClearName] = &Global; @@ -251,21 +259,17 @@ void LLVMTypeHierarchy::constructHierarchy(const llvm::Module &M) { } std::set -LLVMTypeHierarchy::getSubTypes(const llvm::StructType *Type) { +LLVMTypeHierarchy::getSubTypes(const llvm::StructType *Type) const { if (TypeVertexMap.count(Type)) { - return TypeGraph[TypeVertexMap[Type]].ReachableTypes; + if (auto It = TypeVertexMap.find(Type); It != TypeVertexMap.end()) { + return TypeGraph[It->second].ReachableTypes; + } } return {}; } -std::set -LLVMTypeHierarchy::getSuperTypes(const llvm::StructType * /*Type*/) { - std::set ReachableTypes; - // TODO (philipp): what does this function do? - return ReachableTypes; -} - -const llvm::StructType *LLVMTypeHierarchy::getType(std::string TypeName) const { +const llvm::StructType * +LLVMTypeHierarchy::getType(llvm::StringRef TypeName) const { for (auto V : boost::make_iterator_range(boost::vertices(TypeGraph))) { if (TypeGraph[V].Type->getName() == TypeName) { return TypeGraph[V].Type; @@ -274,31 +278,18 @@ const llvm::StructType *LLVMTypeHierarchy::getType(std::string TypeName) const { return nullptr; } -std::set LLVMTypeHierarchy::getAllTypes() const { - std::set Types; +std::vector LLVMTypeHierarchy::getAllTypes() const { + std::vector Types; + Types.reserve(boost::num_vertices(TypeGraph)); for (auto V : boost::make_iterator_range(boost::vertices(TypeGraph))) { - Types.insert(TypeGraph[V].Type); + Types.push_back(TypeGraph[V].Type); } return Types; } -std::string LLVMTypeHierarchy::getTypeName(const llvm::StructType *Type) const { - return Type->getStructName().str(); -} - -bool LLVMTypeHierarchy::hasVFTable(const llvm::StructType *Type) const { - if (TypeVFTMap.count(Type)) { - return !TypeVFTMap.at(Type).empty(); - } - return false; -} - -const LLVMVFTable * -LLVMTypeHierarchy::getVFTable(const llvm::StructType *Type) const { - if (TypeVFTMap.count(Type)) { - return &TypeVFTMap.at(Type); - } - return nullptr; +llvm::StringRef +LLVMTypeHierarchy::getTypeName(const llvm::StructType *Type) const { + return Type->getStructName(); } void LLVMTypeHierarchy::print(llvm::raw_ostream &OS) const { diff --git a/unittests/PhasarLLVM/ControlFlow/CMakeLists.txt b/unittests/PhasarLLVM/ControlFlow/CMakeLists.txt index 656751ae97..77c0d24438 100644 --- a/unittests/PhasarLLVM/ControlFlow/CMakeLists.txt +++ b/unittests/PhasarLLVM/ControlFlow/CMakeLists.txt @@ -10,6 +10,7 @@ set(ControlFlowSources LLVMBasedICFGExportTest.cpp LLVMBasedICFGGlobCtorDtorTest.cpp LLVMBasedICFGSerializationTest.cpp + LLVMVFTableProviderTest.cpp ) set(LLVM_LINK_COMPONENTS Linker) # The CtorDtorTest needs the linker diff --git a/unittests/PhasarLLVM/ControlFlow/LLVMVFTableProviderTest.cpp b/unittests/PhasarLLVM/ControlFlow/LLVMVFTableProviderTest.cpp new file mode 100644 index 0000000000..1cd66805ee --- /dev/null +++ b/unittests/PhasarLLVM/ControlFlow/LLVMVFTableProviderTest.cpp @@ -0,0 +1,172 @@ +#include "phasar/PhasarLLVM/ControlFlow/LLVMVFTableProvider.h" + +#include "phasar/PhasarLLVM/DB/LLVMProjectIRDB.h" +#include "phasar/PhasarLLVM/TypeHierarchy/LLVMVFTable.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Demangle/Demangle.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Module.h" + +#include "TestConfig.h" +#include "gtest/gtest.h" + +using namespace psr; + +namespace { + +using llvm::demangle; + +static const llvm::StructType *getType(const LLVMProjectIRDB &IRDB, + llvm::StringRef Name) { + // TODO: Optimize + for (const auto *Ty : IRDB.getModule()->getIdentifiedStructTypes()) { + if (Ty->getName() == Name) { + return Ty; + } + } + return nullptr; +} + +// check if the vtables are constructed correctly in more complex scenarios + +TEST(VTableTest, VTableConstruction_01) { + LLVMProjectIRDB IRDB({unittest::PathToLLTestFiles + + "type_hierarchies/type_hierarchy_1_cpp.ll"}); + LLVMVFTableProvider TH(IRDB); + // TODO +} + +TEST(VTableTest, VTableConstruction_02) { + LLVMProjectIRDB IRDB({unittest::PathToLLTestFiles + + "type_hierarchies/type_hierarchy_7_cpp.ll"}); + LLVMVFTableProvider TH(IRDB); + // TODO +} + +TEST(VTableTest, VTableConstruction_03) { + LLVMProjectIRDB IRDB({unittest::PathToLLTestFiles + + "type_hierarchies/type_hierarchy_8_cpp.ll"}); + LLVMVFTableProvider TH(IRDB); + + ASSERT_TRUE(TH.hasVFTable(getType(IRDB, "struct.Base"))); + ASSERT_TRUE(TH.hasVFTable(getType(IRDB, "struct.Child"))); + + EXPECT_EQ(demangle(TH.getVFTableOrNull(getType(IRDB, "struct.Base")) + ->getFunction(0) + ->getName() + .str()), + "Base::foo()"); + EXPECT_EQ(demangle(TH.getVFTableOrNull(getType(IRDB, "struct.Base")) + ->getFunction(1) + ->getName() + .str()), + "Base::bar()"); + EXPECT_EQ(TH.getVFTableOrNull(getType(IRDB, "struct.Base"))->size(), 2U); + EXPECT_EQ(demangle(TH.getVFTableOrNull(getType(IRDB, "struct.Child")) + ->getFunction(0) + ->getName() + .str()), + "Child::foo()"); + EXPECT_EQ(demangle(TH.getVFTableOrNull(getType(IRDB, "struct.Child")) + ->getFunction(1) + ->getName() + .str()), + "Base::bar()"); + EXPECT_EQ(demangle(TH.getVFTableOrNull(getType(IRDB, "struct.Child")) + ->getFunction(2) + ->getName() + .str()), + "Child::baz()"); + EXPECT_EQ(TH.getVFTableOrNull(getType(IRDB, "struct.Child"))->size(), 3U); +} + +TEST(VTableTest, VTableConstruction_04) { + LLVMProjectIRDB IRDB({unittest::PathToLLTestFiles + + "type_hierarchies/type_hierarchy_9_cpp.ll"}); + LLVMVFTableProvider TH(IRDB); + + ASSERT_TRUE(TH.hasVFTable(getType(IRDB, "struct.Base"))); + ASSERT_TRUE(TH.hasVFTable(getType(IRDB, "struct.Child"))); + + EXPECT_EQ(demangle(TH.getVFTableOrNull(getType(IRDB, "struct.Base")) + ->getFunction(0) + ->getName() + .str()), + "Base::foo()"); + EXPECT_EQ(demangle(TH.getVFTableOrNull(getType(IRDB, "struct.Base")) + ->getFunction(1) + ->getName() + .str()), + "Base::bar()"); + EXPECT_EQ(TH.getVFTableOrNull(getType(IRDB, "struct.Base"))->size(), 2U); + EXPECT_EQ(demangle(TH.getVFTableOrNull(getType(IRDB, "struct.Child")) + ->getFunction(0) + ->getName() + .str()), + "Child::foo()"); + EXPECT_EQ(demangle(TH.getVFTableOrNull(getType(IRDB, "struct.Child")) + ->getFunction(1) + ->getName() + .str()), + "Base::bar()"); + EXPECT_EQ(demangle(TH.getVFTableOrNull(getType(IRDB, "struct.Child")) + ->getFunction(2) + ->getName() + .str()), + "Child::baz()"); + EXPECT_EQ(TH.getVFTableOrNull(getType(IRDB, "struct.Child"))->size(), 3U); +} + +TEST(VTableTest, VTableConstruction_05) { + LLVMProjectIRDB IRDB({unittest::PathToLLTestFiles + + "type_hierarchies/type_hierarchy_10_cpp.ll"}); + LLVMVFTableProvider TH(IRDB); + + ASSERT_TRUE(TH.hasVFTable(getType(IRDB, "struct.Base"))); + ASSERT_TRUE(TH.hasVFTable(getType(IRDB, "struct.Child"))); + + EXPECT_EQ(demangle(TH.getVFTableOrNull(getType(IRDB, "struct.Base")) + ->getFunction(0) + ->getName() + .str()), + "__cxa_pure_virtual"); + EXPECT_EQ(demangle(TH.getVFTableOrNull(getType(IRDB, "struct.Base")) + ->getFunction(1) + ->getName() + .str()), + "Base::bar()"); + EXPECT_EQ(TH.getVFTableOrNull(getType(IRDB, "struct.Base"))->size(), 2U); + EXPECT_EQ(demangle(TH.getVFTableOrNull(getType(IRDB, "struct.Child")) + ->getFunction(0) + ->getName() + .str()), + "Child::foo()"); + EXPECT_EQ(demangle(TH.getVFTableOrNull(getType(IRDB, "struct.Child")) + ->getFunction(1) + ->getName() + .str()), + "Base::bar()"); + EXPECT_EQ(demangle(TH.getVFTableOrNull(getType(IRDB, "struct.Child")) + ->getFunction(2) + ->getName() + .str()), + "Child::baz()"); + EXPECT_EQ(TH.getVFTableOrNull(getType(IRDB, "struct.Child"))->size(), 3U); +} + +TEST(VTableTest, VTableConstruction_6) { + LLVMProjectIRDB IRDB({unittest::PathToLLTestFiles + + "type_hierarchies/type_hierarchy_14_cpp.ll"}); + + LLVMVFTableProvider TH(IRDB); + + ASSERT_TRUE(TH.hasVFTable(getType(IRDB, "class.Base"))); + EXPECT_EQ(TH.getVFTableOrNull(getType(IRDB, "class.Base"))->size(), 3U); +} +} // namespace + +int main(int Argc, char **Argv) { + ::testing::InitGoogleTest(&Argc, Argv); + return RUN_ALL_TESTS(); +} diff --git a/unittests/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchyTest.cpp b/unittests/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchyTest.cpp index 5b97f15e86..221816582e 100644 --- a/unittests/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchyTest.cpp +++ b/unittests/PhasarLLVM/TypeHierarchy/DIBasedTypeHierarchyTest.cpp @@ -633,783 +633,6 @@ TEST(DBTHTest, BasicTHReconstruction_21) { EXPECT_TRUE(SubTypesBase3.find(Child2Type) != SubTypesBase3.end()); } -/* ------------------------- -VTableConstruction Tests ------------------------- -*/ - -TEST(DBTHTest, VTableConstruction_1) { - LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_1_cpp_dbg.ll"); - DIBasedTypeHierarchy DBTH(IRDB); - - // check for all types - const auto &BaseType = DBTH.getType("Base"); - ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); - ASSERT_NE(nullptr, ChildType); - - ASSERT_TRUE(DBTH.hasVFTable(BaseType)); - ASSERT_TRUE(DBTH.hasVFTable(ChildType)); - - const auto &VTableForBase = DBTH.getVFTable(BaseType); - ASSERT_NE(nullptr, VTableForBase); - ASSERT_NE(nullptr, VTableForBase->getFunction(0)); - EXPECT_EQ(VTableForBase->getFunction(0)->getName(), "_ZN4Base3fooEv"); - - const auto &VTableForChild = DBTH.getVFTable(ChildType); - ASSERT_NE(nullptr, VTableForChild); - ASSERT_NE(nullptr, VTableForChild->getFunction(0)); - EXPECT_EQ(VTableForChild->getFunction(0)->getName(), "_ZN5Child3fooEv"); -} - -TEST(DBTHTest, VTableConstruction_2) { - LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_2_cpp_dbg.ll"); - DIBasedTypeHierarchy DBTH(IRDB); - - // check for all types - const auto &BaseType = DBTH.getType("Base"); - ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); - ASSERT_NE(nullptr, ChildType); - - ASSERT_TRUE(DBTH.hasVFTable(BaseType)); - ASSERT_TRUE(DBTH.hasVFTable(ChildType)); - - const auto &VTableForBase = DBTH.getVFTable(BaseType); - ASSERT_NE(nullptr, VTableForBase); - ASSERT_NE(nullptr, VTableForBase->getFunction(0)); - EXPECT_EQ(VTableForBase->getFunction(0)->getName(), "_ZN4Base3fooEv"); - - const auto &VTableForChild = DBTH.getVFTable(ChildType); - ASSERT_NE(nullptr, VTableForChild); - ASSERT_NE(nullptr, VTableForChild->getFunction(0)); - EXPECT_EQ(VTableForChild->getFunction(0)->getName(), "_ZN5Child3fooEv"); -} - -TEST(DBTHTest, VTableConstruction_3) { - LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_3_cpp_dbg.ll"); - DIBasedTypeHierarchy DBTH(IRDB); - - // check for all types - const auto &BaseType = DBTH.getType("Base"); - ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); - ASSERT_NE(nullptr, ChildType); - - ASSERT_TRUE(DBTH.hasVFTable(BaseType)); - ASSERT_TRUE(DBTH.hasVFTable(ChildType)); - - const auto &VTableForBase = DBTH.getVFTable(BaseType); - ASSERT_NE(nullptr, VTableForBase); - ASSERT_NE(nullptr, VTableForBase->getFunction(0)); - ASSERT_NE(nullptr, VTableForBase->getFunction(1)); - EXPECT_EQ(VTableForBase->getFunction(0)->getName(), "_ZN4Base3fooEv"); - EXPECT_EQ(VTableForBase->getFunction(1)->getName(), "_ZN4Base3barEv"); - - const auto &VTableForChild = DBTH.getVFTable(ChildType); - ASSERT_NE(nullptr, VTableForChild); - ASSERT_NE(nullptr, VTableForChild->getFunction(0)); - EXPECT_EQ(VTableForChild->getFunction(0)->getName(), "_ZN5Child3fooEv"); -} - -TEST(DBTHTest, VTableConstruction_4) { - LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_4_cpp_dbg.ll"); - DIBasedTypeHierarchy DBTH(IRDB); - - // check for all types - const auto &BaseType = DBTH.getType("Base"); - ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); - ASSERT_NE(nullptr, ChildType); - - ASSERT_TRUE(DBTH.hasVFTable(BaseType)); - ASSERT_TRUE(DBTH.hasVFTable(ChildType)); - - const auto &VTableForBase = DBTH.getVFTable(BaseType); - ASSERT_NE(nullptr, VTableForBase); - ASSERT_NE(nullptr, VTableForBase->getFunction(0)); - ASSERT_NE(nullptr, VTableForBase->getFunction(1)); - EXPECT_EQ(VTableForBase->getFunction(0)->getName(), "_ZN4Base3fooEv"); - EXPECT_EQ(VTableForBase->getFunction(1)->getName(), "_ZN4Base3barEv"); - - const auto &VTableForChild = DBTH.getVFTable(ChildType); - ASSERT_NE(nullptr, VTableForChild); - ASSERT_NE(nullptr, VTableForChild->getFunction(0)); - EXPECT_TRUE(VTableForChild->getFunction(1) == nullptr); - ASSERT_NE(nullptr, VTableForChild->getFunction(2)); - EXPECT_EQ(VTableForChild->getFunction(0)->getName(), "_ZN5Child3fooEv"); - EXPECT_EQ(VTableForChild->getFunction(2)->getName(), "_ZN5Child3tarEv"); -} - -TEST(DBTHTest, VTableConstruction_5) { - LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_5_cpp_dbg.ll"); - DIBasedTypeHierarchy DBTH(IRDB); - - // check for all types - const auto &BaseType = DBTH.getType("Base"); - ASSERT_NE(nullptr, BaseType); - const auto &OtherBaseType = DBTH.getType("OtherBase"); - ASSERT_NE(nullptr, OtherBaseType); - const auto &ChildType = DBTH.getType("Child"); - ASSERT_NE(nullptr, ChildType); - - ASSERT_TRUE(DBTH.hasVFTable(BaseType)); - ASSERT_TRUE(DBTH.hasVFTable(OtherBaseType)); - ASSERT_TRUE(DBTH.hasVFTable(ChildType)); - - const auto &VTableForBase = DBTH.getVFTable(BaseType); - ASSERT_NE(nullptr, VTableForBase); - ASSERT_NE(nullptr, VTableForBase->getFunction(0)); - ASSERT_NE(nullptr, VTableForBase->getFunction(1)); - EXPECT_EQ(VTableForBase->getFunction(0)->getName(), "_ZN4Base3fooEv"); - EXPECT_EQ(VTableForBase->getFunction(1)->getName(), "_ZN4Base3barEv"); - - const auto &VTableForOtherBase = DBTH.getVFTable(OtherBaseType); - ASSERT_NE(nullptr, VTableForOtherBase); - ASSERT_NE(nullptr, VTableForOtherBase->getFunction(0)); - EXPECT_EQ(VTableForOtherBase->getFunction(0)->getName(), - "_ZN9OtherBase3bazEv"); - - const auto &VTableForChild = DBTH.getVFTable(ChildType); - ASSERT_NE(nullptr, VTableForChild); - ASSERT_NE(nullptr, VTableForChild->getFunction(0)); - EXPECT_TRUE(VTableForChild->getFunction(1) == nullptr); - ASSERT_NE(nullptr, VTableForChild->getFunction(2)); - ASSERT_NE(nullptr, VTableForChild->getFunction(3)); - EXPECT_EQ(VTableForChild->getFunction(0)->getName(), "_ZN5Child3fooEv"); - EXPECT_EQ(VTableForChild->getFunction(2)->getName(), "_ZN5Child3bazEv"); - EXPECT_EQ(VTableForChild->getFunction(3)->getName(), "_ZN5Child3tarEv"); -} - -TEST(DBTHTest, VTableConstruction_6) { - LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_6_cpp_dbg.ll"); - DIBasedTypeHierarchy DBTH(IRDB); - - const auto &BaseType = DBTH.getType("Base"); - ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); - ASSERT_NE(nullptr, ChildType); - - const auto &VTableForBase = DBTH.getVFTable(BaseType); - ASSERT_NE(nullptr, VTableForBase); - ASSERT_NE(nullptr, VTableForBase->getFunction(0)); - ASSERT_NE(nullptr, VTableForBase->getFunction(1)); - EXPECT_EQ(VTableForBase->getFunction(0)->getName(), "_ZN4Base3fooEv"); - EXPECT_EQ(VTableForBase->getFunction(1)->getName(), "_ZN4Base3barEv"); - - const auto &VTableForChild = DBTH.getVFTable(ChildType); - ASSERT_NE(nullptr, VTableForChild); - ASSERT_NE(nullptr, VTableForChild->getFunction(0)); - EXPECT_TRUE(VTableForChild->getFunction(1) == nullptr); - ASSERT_NE(nullptr, VTableForChild->getFunction(2)); - EXPECT_EQ(VTableForChild->getFunction(0)->getName(), "_ZN5Child3fooEv"); - EXPECT_EQ(VTableForChild->getFunction(2)->getName(), "_ZN5Child3tarEv"); -} - -TEST(DBTHTest, VTableConstruction_7) { - LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_7_cpp_dbg.ll"); - DIBasedTypeHierarchy DBTH(IRDB); - - // check for all types - const auto &AType = DBTH.getType("A"); - ASSERT_NE(nullptr, AType); - const auto &BType = DBTH.getType("B"); - ASSERT_NE(nullptr, BType); - const auto &CType = DBTH.getType("C"); - ASSERT_NE(nullptr, CType); - const auto &DType = DBTH.getType("D"); - ASSERT_NE(nullptr, DType); - const auto &XType = DBTH.getType("X"); - ASSERT_NE(nullptr, XType); - const auto &YType = DBTH.getType("Y"); - ASSERT_NE(nullptr, YType); - const auto &ZType = DBTH.getType("Z"); - ASSERT_NE(nullptr, ZType); - - const auto &VTableForAType = DBTH.getVFTable(AType); - ASSERT_NE(nullptr, VTableForAType); - ASSERT_NE(nullptr, VTableForAType->getFunction(0)); - EXPECT_EQ(VTableForAType->getFunction(0)->getName(), "_ZN1A1fEv"); - const auto &VTableForBType = DBTH.getVFTable(BType); - ASSERT_NE(nullptr, VTableForBType); - EXPECT_EQ(VTableForBType->getFunction(0), nullptr); - const auto &VTableForCType = DBTH.getVFTable(CType); - ASSERT_NE(nullptr, VTableForCType); - EXPECT_EQ(VTableForCType->getFunction(0), nullptr); - const auto &VTableForDType = DBTH.getVFTable(DType); - ASSERT_NE(nullptr, VTableForDType); - EXPECT_EQ(VTableForDType->getFunction(0), nullptr); - const auto &VTableForXType = DBTH.getVFTable(XType); - ASSERT_NE(nullptr, VTableForXType); - ASSERT_NE(nullptr, VTableForXType->getFunction(0)); - EXPECT_EQ(VTableForXType->getFunction(0)->getName(), "_ZN1X1gEv"); - const auto &VTableForYType = DBTH.getVFTable(YType); - ASSERT_NE(nullptr, VTableForYType); - EXPECT_EQ(VTableForYType->getFunction(0), nullptr); - const auto &VTableForZType = DBTH.getVFTable(ZType); - ASSERT_NE(nullptr, VTableForZType); - EXPECT_EQ(VTableForZType->getFunction(0), nullptr); -} - -TEST(DBTHTest, VTableConstruction_7_b) { - LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_7_b_cpp_dbg.ll"); - DIBasedTypeHierarchy DBTH(IRDB); - - // check for all types - const auto &AType = DBTH.getType("A"); - ASSERT_NE(nullptr, AType); - const auto &CType = DBTH.getType("C"); - ASSERT_NE(nullptr, CType); - const auto &XType = DBTH.getType("X"); - ASSERT_NE(nullptr, XType); - const auto &YType = DBTH.getType("Y"); - ASSERT_NE(nullptr, YType); - const auto &ZType = DBTH.getType("Z"); - ASSERT_NE(nullptr, ZType); - const auto &OmegaType = DBTH.getType("Omega"); - ASSERT_NE(nullptr, OmegaType); - - const auto &VTableForAType = DBTH.getVFTable(AType); - ASSERT_NE(nullptr, VTableForAType); - ASSERT_NE(nullptr, VTableForAType->getFunction(0)); - EXPECT_EQ(VTableForAType->getFunction(0)->getName(), "_ZN1A1fEv"); - const auto &VTableForCType = DBTH.getVFTable(CType); - ASSERT_NE(nullptr, VTableForCType); - EXPECT_EQ(VTableForCType->getFunction(0), nullptr); - const auto &VTableForXType = DBTH.getVFTable(XType); - ASSERT_NE(nullptr, VTableForXType); - ASSERT_NE(nullptr, VTableForXType->getFunction(0)); - EXPECT_EQ(VTableForXType->getFunction(0)->getName(), "_ZN1X1gEv"); - const auto &VTableForYType = DBTH.getVFTable(YType); - ASSERT_NE(nullptr, VTableForYType); - EXPECT_EQ(VTableForYType->getFunction(0), nullptr); - const auto &VTableForZType = DBTH.getVFTable(ZType); - ASSERT_NE(nullptr, VTableForZType); - EXPECT_EQ(VTableForZType->getFunction(0), nullptr); - const auto &VTableForOmegaType = DBTH.getVFTable(OmegaType); - ASSERT_NE(nullptr, VTableForOmegaType); - ASSERT_NE(nullptr, VTableForOmegaType->getFunction(0)); - EXPECT_EQ(VTableForOmegaType->getFunction(0)->getName(), "_ZN5Omega1fEv"); -} - -TEST(DBTHTest, VTableConstruction_8) { - LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_8_cpp_dbg.ll"); - DIBasedTypeHierarchy DBTH(IRDB); - - // check for all types - const auto &BaseType = DBTH.getType("Base"); - ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); - ASSERT_NE(nullptr, ChildType); - const auto &NonvirtualClassType = DBTH.getType("NonvirtualClass"); - EXPECT_NE(nullptr, NonvirtualClassType); - const auto &NonvirtualStructType = DBTH.getType("NonvirtualStruct"); - EXPECT_NE(nullptr, NonvirtualStructType); - - const auto &VTableForBaseType = DBTH.getVFTable(BaseType); - ASSERT_NE(nullptr, VTableForBaseType); - ASSERT_NE(nullptr, VTableForBaseType->getFunction(0)); - ASSERT_NE(nullptr, VTableForBaseType->getFunction(1)); - EXPECT_EQ(VTableForBaseType->getFunction(0)->getName(), "_ZN4Base3fooEv"); - EXPECT_EQ(VTableForBaseType->getFunction(1)->getName(), "_ZN4Base3barEv"); - const auto &VTableForChildType = DBTH.getVFTable(ChildType); - ASSERT_NE(nullptr, VTableForChildType); - ASSERT_NE(nullptr, VTableForChildType->getFunction(0)); - EXPECT_EQ(VTableForChildType->getFunction(1), nullptr); - ASSERT_NE(nullptr, VTableForChildType->getFunction(2)); - EXPECT_EQ(VTableForChildType->getFunction(0)->getName(), "_ZN5Child3fooEv"); - EXPECT_EQ(VTableForChildType->getFunction(2)->getName(), "_ZN5Child3bazEv"); - - const auto &VTableForNonvirtualClassType = - DBTH.getVFTable(NonvirtualClassType); - ASSERT_NE(nullptr, VTableForNonvirtualClassType); - EXPECT_EQ(VTableForNonvirtualClassType->getFunction(0), nullptr); - const auto &VTableForNonvirtualStructType = - DBTH.getVFTable(NonvirtualStructType); - ASSERT_NE(nullptr, VTableForNonvirtualStructType); - EXPECT_EQ(VTableForNonvirtualStructType->getFunction(0), nullptr); -} - -TEST(DBTHTest, VTableConstruction_9) { - LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_9_cpp_dbg.ll"); - DIBasedTypeHierarchy DBTH(IRDB); - - const auto &BaseType = DBTH.getType("Base"); - ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); - ASSERT_NE(nullptr, ChildType); - - const auto &VTableForBase = DBTH.getVFTable(BaseType); - ASSERT_NE(nullptr, VTableForBase); - ASSERT_NE(nullptr, VTableForBase->getFunction(0)); - ASSERT_NE(nullptr, VTableForBase->getFunction(1)); - EXPECT_EQ(VTableForBase->getFunction(0)->getName(), "_ZN4Base3fooEv"); - EXPECT_EQ(VTableForBase->getFunction(1)->getName(), "_ZN4Base3barEv"); - - const auto &VTableForChild = DBTH.getVFTable(ChildType); - ASSERT_NE(nullptr, VTableForChild); - ASSERT_NE(nullptr, VTableForChild->getFunction(0)); - EXPECT_TRUE(VTableForChild->getFunction(1) == nullptr); - ASSERT_NE(nullptr, VTableForChild->getFunction(2)); - EXPECT_EQ(VTableForChild->getFunction(0)->getName(), "_ZN5Child3fooEv"); - EXPECT_EQ(VTableForChild->getFunction(2)->getName(), "_ZN5Child3bazEv"); -} - -TEST(DBTHTest, VTableConstruction_10) { - LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_10_cpp_dbg.ll"); - DIBasedTypeHierarchy DBTH(IRDB); - - // check for all types - const auto &BaseType = DBTH.getType("Base"); - ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); - ASSERT_NE(nullptr, ChildType); - - const auto &VTableForBase = DBTH.getVFTable(BaseType); - ASSERT_NE(nullptr, VTableForBase); - EXPECT_EQ(VTableForBase->getFunction(0), nullptr); - ASSERT_NE(nullptr, VTableForBase->getFunction(1)); - EXPECT_EQ(VTableForBase->getFunction(1)->getName(), "_ZN4Base3barEv"); - - const auto &VTableForChild = DBTH.getVFTable(ChildType); - ASSERT_NE(nullptr, VTableForChild); - ASSERT_NE(nullptr, VTableForChild->getFunction(0)); - EXPECT_TRUE(VTableForChild->getFunction(1) == nullptr); - ASSERT_NE(nullptr, VTableForChild->getFunction(2)); - EXPECT_EQ(VTableForChild->getFunction(0)->getName(), "_ZN5Child3fooEv"); - EXPECT_EQ(VTableForChild->getFunction(2)->getName(), "_ZN5Child3bazEv"); -} - -TEST(DBTHTest, VTableConstruction_11) { - LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_11_cpp_dbg.ll"); - DIBasedTypeHierarchy DBTH(IRDB); - - // check for all types - const auto &BaseType = DBTH.getType("Base"); - ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); - ASSERT_NE(nullptr, ChildType); - - const auto &VTableForBase = DBTH.getVFTable(BaseType); - ASSERT_NE(nullptr, VTableForBase); - ASSERT_NE(nullptr, VTableForBase->getFunction(0)); - EXPECT_EQ(VTableForBase->getFunction(0)->getName(), "_ZN4Base3fooEv"); - - const auto &VTableForChild = DBTH.getVFTable(ChildType); - ASSERT_NE(nullptr, VTableForChild); - ASSERT_NE(nullptr, VTableForChild->getFunction(0)); - EXPECT_EQ(VTableForChild->getFunction(0)->getName(), "_ZN5Child3fooEv"); -} - -TEST(DBTHTest, VTableConstruction_12) { - LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_12_cpp_dbg.ll"); - DIBasedTypeHierarchy DBTH(IRDB); - - // check for all types - const auto &BaseType = DBTH.getType("Base"); - ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); - ASSERT_NE(nullptr, ChildType); - - const auto &VTableForBase = DBTH.getVFTable(BaseType); - ASSERT_NE(nullptr, VTableForBase); - ASSERT_NE(nullptr, VTableForBase->getFunction(0)); - EXPECT_EQ(VTableForBase->getFunction(0)->getName(), "_ZN4Base3fooEv"); - - const auto &VTableForChild = DBTH.getVFTable(ChildType); - ASSERT_NE(nullptr, VTableForChild); - ASSERT_NE(nullptr, VTableForChild->getFunction(0)); - EXPECT_EQ(VTableForChild->getFunction(0)->getName(), "_ZN5Child3fooEv"); -} - -TEST(DBTHTest, VTableConstruction_12_b) { - LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_12_b_cpp_dbg.ll"); - DIBasedTypeHierarchy DBTH(IRDB); - - // check for all types - const auto &BaseType = DBTH.getType("Base"); - ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); - ASSERT_NE(nullptr, ChildType); - const auto &ChildsChildType = DBTH.getType("ChildsChild"); - ASSERT_NE(nullptr, ChildsChildType); - - const auto &VTableForBase = DBTH.getVFTable(BaseType); - ASSERT_NE(nullptr, VTableForBase); - EXPECT_EQ(VTableForBase->getFunction(0), nullptr); - - const auto &VTableForChild = DBTH.getVFTable(ChildType); - ASSERT_NE(nullptr, VTableForChild); - EXPECT_EQ(VTableForChild->getFunction(0), nullptr); - - const auto &VTableForChildsChild = DBTH.getVFTable(ChildsChildType); - ASSERT_NE(nullptr, VTableForChildsChild); - ASSERT_NE(nullptr, VTableForChildsChild->getFunction(0)); - EXPECT_EQ(VTableForChildsChild->getFunction(0)->getName(), - "_ZN11ChildsChild3fooEv"); -} - -TEST(DBTHTest, VTableConstruction_12_c) { - LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_12_c_cpp_dbg.ll"); - DIBasedTypeHierarchy DBTH(IRDB); - - // check for all types - const auto &ChildType = DBTH.getType("Child"); - ASSERT_NE(nullptr, ChildType); - const auto &ChildsChildType = DBTH.getType("ChildsChild"); - ASSERT_NE(nullptr, ChildsChildType); - - const auto &VTableForChild = DBTH.getVFTable(ChildType); - ASSERT_NE(nullptr, VTableForChild); - ASSERT_NE(nullptr, VTableForChild->getFunction(0)); - EXPECT_EQ(VTableForChild->getFunction(0)->getName(), "_ZN5Child3fooEv"); - - const auto &VTableForChildsChild = DBTH.getVFTable(ChildsChildType); - ASSERT_NE(nullptr, VTableForChildsChild); - EXPECT_EQ(VTableForChildsChild->getFunction(0), nullptr); -} - -/* -TEST(DBTHTest, VTableConstruction_13) { - Test file 13 has no types -} -*/ - -TEST(DBTHTest, VTableConstruction_14) { - LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_14_cpp_dbg.ll"); - DIBasedTypeHierarchy DBTH(IRDB); - - // check for all types - const auto &BaseType = DBTH.getType("Base"); - ASSERT_NE(nullptr, BaseType); - - const auto &VTableForBase = DBTH.getVFTable(BaseType); - ASSERT_NE(nullptr, VTableForBase); - ASSERT_NE(nullptr, VTableForBase->getFunction(0)); - EXPECT_EQ(VTableForBase->getFunction(0)->getName(), "_ZN4Base4testEv"); -} - -TEST(DBTHTest, VTableConstruction_15) { - LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_15_cpp_dbg.ll"); - DIBasedTypeHierarchy DBTH(IRDB); - - // check for all types - const auto &BaseType = DBTH.getType("Base"); - ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); - ASSERT_NE(nullptr, ChildType); - - const auto &VTableForBase = DBTH.getVFTable(BaseType); - ASSERT_NE(nullptr, VTableForBase); - ASSERT_NE(nullptr, VTableForBase->getFunction(0)); - EXPECT_EQ(VTableForBase->getFunction(0)->getName(), "_ZN4Base4testEv"); - - const auto &VTableForChild = DBTH.getVFTable(ChildType); - ASSERT_NE(nullptr, VTableForChild); - EXPECT_EQ(VTableForChild->getFunction(0), nullptr); -} - -TEST(DBTHTest, VTableConstruction_16) { - LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_16_cpp_dbg.ll"); - DIBasedTypeHierarchy DBTH(IRDB); - - // check for all types - const auto &BaseType = DBTH.getType("Base"); - ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); - ASSERT_NE(nullptr, ChildType); - const auto &ChildOfChildType = DBTH.getType("ChildOfChild"); - ASSERT_NE(nullptr, ChildOfChildType); - const auto &BaseTwoType = DBTH.getType("BaseTwo"); - ASSERT_NE(nullptr, BaseTwoType); - const auto &ChildTwoType = DBTH.getType("ChildTwo"); - ASSERT_NE(nullptr, ChildTwoType); - - const auto &VTableForBase = DBTH.getVFTable(BaseType); - ASSERT_NE(nullptr, VTableForBase); - ASSERT_NE(nullptr, VTableForBase->getFunction(0)); - EXPECT_EQ(VTableForBase->getFunction(0)->getName(), "_ZN4Base3fooEv"); - - const auto &VTableForChild = DBTH.getVFTable(ChildType); - ASSERT_NE(nullptr, VTableForChild); - ASSERT_NE(nullptr, VTableForChild->getFunction(0)); - EXPECT_EQ(VTableForChild->getFunction(0)->getName(), "_ZN5Child3fooEv"); - - const auto &VTableForChildOfChild = DBTH.getVFTable(ChildOfChildType); - ASSERT_NE(nullptr, VTableForChildOfChild); - EXPECT_EQ(VTableForChildOfChild->getFunction(0), nullptr); - - const auto &VTableForBaseTwo = DBTH.getVFTable(BaseTwoType); - ASSERT_NE(nullptr, VTableForBaseTwo); - ASSERT_NE(nullptr, VTableForBaseTwo->getFunction(0)); - EXPECT_EQ(VTableForBaseTwo->getFunction(0)->getName(), - "_ZN7BaseTwo6foobarEv"); - - const auto &VTableForChildTwo = DBTH.getVFTable(ChildTwoType); - ASSERT_NE(nullptr, VTableForChildTwo); - ASSERT_NE(nullptr, VTableForChildTwo->getFunction(0)); - EXPECT_EQ(VTableForChildTwo->getFunction(0)->getName(), - "_ZN8ChildTwo6foobarEv"); -} - -TEST(DBTHTest, VTableConstruction_17) { - LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_17_cpp_dbg.ll"); - DIBasedTypeHierarchy DBTH(IRDB); - - // check for all types - const auto &BaseType = DBTH.getType("Base"); - ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); - ASSERT_NE(nullptr, ChildType); - // Since Child2 is never used, it is sometimes optimized out by the compiler - // const auto &Child2Type = DBTH.getType("Child2"); - // ASSERT_NE(nullptr, Child2Type); - const auto &Base2Type = DBTH.getType("Base2"); - ASSERT_NE(nullptr, Base2Type); - const auto &KidType = DBTH.getType("Kid"); - ASSERT_NE(nullptr, KidType); - - const auto &VTableForBase = DBTH.getVFTable(BaseType); - EXPECT_EQ(VTableForBase->getFunction(0), nullptr); - ASSERT_NE(nullptr, VTableForBase->getFunction(1)); - EXPECT_EQ(VTableForBase->getFunction(1)->getName(), "_ZN4Base3barEv"); - - const auto &VTableForChild = DBTH.getVFTable(ChildType); - ASSERT_NE(nullptr, VTableForChild); - ASSERT_NE(nullptr, VTableForChild->getFunction(0)); - EXPECT_EQ(VTableForChild->getFunction(1), nullptr); - ASSERT_NE(nullptr, VTableForChild->getFunction(2)); - EXPECT_EQ(VTableForChild->getFunction(0)->getName(), "_ZN5Child3fooEv"); - EXPECT_EQ(VTableForChild->getFunction(2)->getName(), "_ZN5Child3bazEv"); - - const auto &VTableForBase2 = DBTH.getVFTable(Base2Type); - ASSERT_NE(nullptr, VTableForBase2); - EXPECT_EQ(VTableForBase2->getFunction(0), nullptr); - ASSERT_NE(nullptr, VTableForBase2->getFunction(1)); - EXPECT_EQ(VTableForBase2->getFunction(2), nullptr); - ASSERT_NE(nullptr, VTableForBase2->getFunction(3)); - EXPECT_EQ(VTableForBase2->getFunction(1)->getName(), "_ZN5Base23barEv"); - EXPECT_EQ(VTableForBase2->getFunction(3)->getName(), "_ZN5Base26foobarEv"); - - const auto &VTableForKid = DBTH.getVFTable(KidType); - ASSERT_NE(nullptr, VTableForKid); - ASSERT_NE(nullptr, VTableForKid->getFunction(0)); - EXPECT_EQ(VTableForKid->getFunction(1), nullptr); - ASSERT_NE(nullptr, VTableForKid->getFunction(2)); - EXPECT_EQ(VTableForKid->getFunction(3), nullptr); - ASSERT_NE(nullptr, VTableForKid->getFunction(4)); - EXPECT_EQ(VTableForKid->getFunction(0)->getName(), "_ZN3Kid3fooEv"); - EXPECT_EQ(VTableForKid->getFunction(2)->getName(), "_ZN3Kid6barfooEv"); - EXPECT_EQ(VTableForKid->getFunction(4)->getName(), "_ZN3Kid3bauEv"); -} - -TEST(DBTHTest, VTableConstruction_18) { - LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_18_cpp_dbg.ll"); - DIBasedTypeHierarchy DBTH(IRDB); - - // check for all types - const auto &BaseType = DBTH.getType("Base"); - ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); - ASSERT_NE(nullptr, ChildType); - const auto &Child2Type = DBTH.getType("Child_2"); - ASSERT_NE(nullptr, Child2Type); - const auto &Child3Type = DBTH.getType("Child_3"); - ASSERT_NE(nullptr, Child3Type); - - const auto &VTableForBase = DBTH.getVFTable(BaseType); - ASSERT_NE(nullptr, VTableForBase); - EXPECT_EQ(VTableForBase->getFunction(0), nullptr); - ASSERT_NE(nullptr, VTableForBase->getFunction(1)); - EXPECT_EQ(VTableForBase->getFunction(1)->getName(), "_ZN4Base3barEv"); - - const auto &VTableForChild = DBTH.getVFTable(ChildType); - ASSERT_NE(nullptr, VTableForChild); - ASSERT_NE(nullptr, VTableForChild->getFunction(0)); - EXPECT_EQ(VTableForChild->getFunction(0)->getName(), "_ZN5Child3fooEv"); - - const auto &VTableForChild2 = DBTH.getVFTable(Child2Type); - ASSERT_NE(nullptr, VTableForChild2); - EXPECT_EQ(VTableForChild2->getFunction(0), nullptr); - EXPECT_EQ(VTableForChild2->getFunction(1), nullptr); - // Test - // ASSERT_NE(nullptr, VTableForBase->getFunction(2)); - EXPECT_EQ(VTableForChild2->getFunction(2)->getName(), "_ZN7Child_26foobarEv"); - - const auto &VTableForChild3 = DBTH.getVFTable(Child3Type); - ASSERT_NE(nullptr, VTableForChild3); - EXPECT_EQ(VTableForChild3->getFunction(0), nullptr); - EXPECT_EQ(VTableForChild3->getFunction(1), nullptr); - EXPECT_EQ(VTableForChild3->getFunction(2), nullptr); - ASSERT_NE(nullptr, VTableForChild3->getFunction(3)); - EXPECT_EQ(VTableForChild3->getFunction(3)->getName(), "_ZN7Child_36barfooEv"); -} - -TEST(DBTHTest, VTableConstruction_19) { - LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_19_cpp_dbg.ll"); - DIBasedTypeHierarchy DBTH(IRDB); - - // check for all types - const auto &BaseType = DBTH.getType("Base"); - ASSERT_NE(nullptr, BaseType); - const auto &ChildType = DBTH.getType("Child"); - ASSERT_NE(nullptr, ChildType); - const auto &FooType = DBTH.getType("Foo"); - ASSERT_NE(nullptr, FooType); - const auto &BarType = DBTH.getType("Bar"); - ASSERT_NE(nullptr, BarType); - const auto &LoremType = DBTH.getType("Lorem"); - ASSERT_NE(nullptr, LoremType); - const auto &ImpsumType = DBTH.getType("Impsum"); - ASSERT_NE(nullptr, ImpsumType); - - const auto &VTableForBase = DBTH.getVFTable(BaseType); - ASSERT_NE(nullptr, VTableForBase); - ASSERT_NE(nullptr, VTableForBase->getFunction(0)); - EXPECT_EQ(VTableForBase->getFunction(0)->getName(), "_ZN4Base10publicbaseEv"); - - const auto &VTableForChild = DBTH.getVFTable(ChildType); - ASSERT_NE(nullptr, VTableForChild); - ASSERT_NE(nullptr, VTableForChild->getFunction(0)); - EXPECT_EQ(VTableForChild->getFunction(0)->getName(), - "_ZN5Child10publicbaseEv"); - - const auto &VTableForBar = DBTH.getVFTable(BarType); - ASSERT_NE(nullptr, VTableForBar); - ASSERT_NE(nullptr, VTableForBar->getFunction(0)); - EXPECT_EQ(VTableForBar->getFunction(0)->getName(), "_ZN3Bar12protectedfooEv"); - - const auto &VTableForFoo = DBTH.getVFTable(FooType); - ASSERT_NE(nullptr, VTableForFoo); - ASSERT_NE(nullptr, VTableForFoo->getFunction(0)); - EXPECT_EQ(VTableForFoo->getFunction(0)->getName(), "_ZN3Foo12protectedfooEv"); - - const auto &VTableForLorem = DBTH.getVFTable(LoremType); - ASSERT_NE(nullptr, VTableForLorem); - ASSERT_NE(nullptr, VTableForLorem->getFunction(0)); - EXPECT_EQ(VTableForLorem->getFunction(0)->getName(), - "_ZN5Lorem12privateloremEv"); - - const auto &VTableForImpsum = DBTH.getVFTable(ImpsumType); - ASSERT_NE(nullptr, VTableForImpsum); - ASSERT_NE(nullptr, VTableForImpsum->getFunction(0)); - EXPECT_EQ(VTableForImpsum->getFunction(0)->getName(), - "_ZN6Impsum12privateloremEv"); -} - -TEST(DBTHTest, VTableConstruction_20) { - LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_20_cpp_dbg.ll"); - DIBasedTypeHierarchy DBTH(IRDB); - - // check for all types - const auto &BaseType = DBTH.getType("Base"); - ASSERT_NE(nullptr, BaseType); - const auto &Base2Type = DBTH.getType("Base2"); - ASSERT_NE(nullptr, Base2Type); - const auto &ChildType = DBTH.getType("Child"); - ASSERT_NE(nullptr, ChildType); - - const auto &VTableForBase = DBTH.getVFTable(BaseType); - ASSERT_NE(nullptr, VTableForBase); - EXPECT_EQ(VTableForBase->getFunction(0), nullptr); - ASSERT_NE(nullptr, VTableForBase->getFunction(1)); - EXPECT_EQ(VTableForBase->getFunction(1)->getName(), "_ZN4Base3barEv"); - - const auto &VTableForChild = DBTH.getVFTable(ChildType); - ASSERT_NE(nullptr, VTableForChild); - ASSERT_NE(nullptr, VTableForChild->getFunction(0)); - EXPECT_EQ(VTableForChild->getFunction(1), nullptr); - ASSERT_NE(nullptr, VTableForChild->getFunction(2)); - EXPECT_EQ(VTableForChild->getFunction(0)->getName(), "_ZN5Child3fooEv"); - EXPECT_EQ(VTableForChild->getFunction(2)->getName(), "_ZN5Child4bar2Ev"); - - const auto &VTableForBase2 = DBTH.getVFTable(Base2Type); - ASSERT_NE(nullptr, VTableForBase2); - ASSERT_NE(nullptr, VTableForBase2->getFunction(0)); - EXPECT_EQ(VTableForBase2->getFunction(0)->getName(), "_ZN5Base24foo2Ev"); -} - -TEST(DBTHTest, VTableConstruction_21) { - LLVMProjectIRDB IRDB(unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_21_cpp_dbg.ll"); - DIBasedTypeHierarchy DBTH(IRDB); - - // check for all types - const auto &BaseType = DBTH.getType("Base"); - ASSERT_NE(nullptr, BaseType); - const auto &Base2Type = DBTH.getType("Base2"); - ASSERT_NE(nullptr, Base2Type); - const auto &Base3Type = DBTH.getType("Base3"); - ASSERT_NE(nullptr, Base3Type); - const auto &ChildType = DBTH.getType("Child"); - ASSERT_NE(nullptr, ChildType); - const auto &Child2Type = DBTH.getType("Child2"); - ASSERT_NE(nullptr, Child2Type); - - const auto &VTableForBase = DBTH.getVFTable(BaseType); - ASSERT_NE(nullptr, VTableForBase); - EXPECT_EQ(VTableForBase->getFunction(0), nullptr); - EXPECT_EQ(VTableForBase->getFunction(1), nullptr); - EXPECT_EQ(VTableForBase->getFunction(2), nullptr); - // Test - // ASSERT_NE(nullptr, VTableForBase->getFunction(3)); - EXPECT_EQ(VTableForBase->getFunction(3)->getName(), "_ZN4Base3barEv"); - - const auto &VTableForBase2 = DBTH.getVFTable(Base2Type); - ASSERT_NE(nullptr, VTableForBase2); - EXPECT_EQ(VTableForBase2->getFunction(0), nullptr); - EXPECT_EQ(VTableForBase2->getFunction(1), nullptr); - ASSERT_NE(nullptr, VTableForBase2->getFunction(2)); - EXPECT_EQ(VTableForBase2->getFunction(2)->getName(), "_ZN5Base24foo2Ev"); - - const auto &VTableForBase3 = DBTH.getVFTable(Base3Type); - ASSERT_NE(nullptr, VTableForBase3); - EXPECT_EQ(nullptr, VTableForBase->getFunction(0)); - - const auto &VTableForChild = DBTH.getVFTable(ChildType); - ASSERT_NE(nullptr, VTableForChild); - EXPECT_EQ(VTableForChild->getFunction(0), nullptr); - EXPECT_EQ(VTableForChild->getFunction(1), nullptr); - ASSERT_NE(nullptr, VTableForChild->getFunction(2)); - EXPECT_EQ(VTableForChild->getFunction(2)->getName(), "_ZN5Child3fooEv"); - EXPECT_EQ(VTableForChild->getFunction(3), nullptr); - ASSERT_NE(nullptr, VTableForChild->getFunction(4)); - EXPECT_EQ(VTableForChild->getFunction(4)->getName(), "_ZN5Child4bar2Ev"); - - const auto &VTableForChild2 = DBTH.getVFTable(Child2Type); - ASSERT_NE(nullptr, VTableForChild2); - EXPECT_EQ(VTableForChild2->getFunction(0), nullptr); - EXPECT_EQ(VTableForChild2->getFunction(1), nullptr); - EXPECT_EQ(VTableForChild2->getFunction(2), nullptr); - EXPECT_EQ(VTableForChild2->getFunction(3), nullptr); - EXPECT_EQ(VTableForChild2->getFunction(4), nullptr); - ASSERT_NE(nullptr, VTableForChild2->getFunction(5)); - EXPECT_EQ(VTableForChild2->getFunction(5)->getName(), "_ZN6Child26foobarEv"); -} - /* -------------------------------- TransitivelyReachableTypes Tests diff --git a/unittests/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchyTest.cpp b/unittests/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchyTest.cpp index 3dd219fde1..0fa9a40bda 100644 --- a/unittests/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchyTest.cpp +++ b/unittests/PhasarLLVM/TypeHierarchy/LLVMTypeHierarchyTest.cpp @@ -33,23 +33,7 @@ TEST(LTHTest, BasicTHReconstruction_1) { EXPECT_EQ( LTH.isSubType(LTH.getType("struct.Base"), LTH.getType("struct.Child")), true); - EXPECT_EQ( - LTH.isSuperType(LTH.getType("struct.Child"), LTH.getType("struct.Base")), - true); - EXPECT_EQ(LTH.hasVFTable(LTH.getType("struct.Base")), true); - EXPECT_EQ(LTH.hasVFTable(LTH.getType("struct.Child")), true); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Base")) - ->getFunction(0) - ->getName() - .str(), - "_ZN4Base3fooEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Child")) - ->getFunction(0) - ->getName() - .str(), - "_ZN5Child3fooEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Base"))->size(), 1U); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Child"))->size(), 1U); + EXPECT_EQ(LTH.getSubTypes(LTH.getType("struct.Base")).size(), 2U); EXPECT_EQ(LTH.getSubTypes(LTH.getType("struct.Child")).size(), 1U); auto BaseReachable = LTH.getSubTypes(LTH.getType("struct.Base")); @@ -75,23 +59,7 @@ TEST(LTHTest, BasicTHReconstruction_2) { EXPECT_EQ( LTH.isSubType(LTH.getType("struct.Base"), LTH.getType("struct.Child")), true); - EXPECT_EQ( - LTH.isSuperType(LTH.getType("struct.Child"), LTH.getType("struct.Base")), - true); - EXPECT_EQ(LTH.hasVFTable(LTH.getType("struct.Base")), true); - EXPECT_EQ(LTH.hasVFTable(LTH.getType("struct.Child")), true); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Base")) - ->getFunction(0) - ->getName() - .str(), - "_ZN4Base3fooEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Child")) - ->getFunction(0) - ->getName() - .str(), - "_ZN5Child3fooEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Base"))->size(), 1U); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Child"))->size(), 1U); + EXPECT_EQ(LTH.getSubTypes(LTH.getType("struct.Base")).size(), 2U); EXPECT_EQ(LTH.getSubTypes(LTH.getType("struct.Child")).size(), 1U); auto BaseReachable = LTH.getSubTypes(LTH.getType("struct.Base")); @@ -111,33 +79,7 @@ TEST(LTHTest, BasicTHReconstruction_3) { EXPECT_EQ( LTH.isSubType(LTH.getType("struct.Base"), LTH.getType("struct.Child")), true); - EXPECT_EQ( - LTH.isSuperType(LTH.getType("struct.Child"), LTH.getType("struct.Base")), - true); - EXPECT_EQ(LTH.hasVFTable(LTH.getType("struct.Base")), true); - EXPECT_EQ(LTH.hasVFTable(LTH.getType("struct.Child")), true); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Base")) - ->getFunction(0) - ->getName() - .str(), - "_ZN4Base3fooEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Base")) - ->getFunction(1) - ->getName() - .str(), - "_ZN4Base3barEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Child")) - ->getFunction(0) - ->getName() - .str(), - "_ZN5Child3fooEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Child")) - ->getFunction(1) - ->getName() - .str(), - "_ZN4Base3barEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Base"))->size(), 2U); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Child"))->size(), 2U); + EXPECT_EQ(LTH.getSubTypes(LTH.getType("struct.Base")).size(), 2U); EXPECT_EQ(LTH.getSubTypes(LTH.getType("struct.Child")).size(), 1U); auto BaseReachable = LTH.getSubTypes(LTH.getType("struct.Base")); @@ -157,38 +99,7 @@ TEST(LTHTest, BasicTHReconstruction_4) { EXPECT_EQ( LTH.isSubType(LTH.getType("struct.Base"), LTH.getType("struct.Child")), true); - EXPECT_EQ( - LTH.isSuperType(LTH.getType("struct.Child"), LTH.getType("struct.Base")), - true); - EXPECT_EQ(LTH.hasVFTable(LTH.getType("struct.Base")), true); - EXPECT_EQ(LTH.hasVFTable(LTH.getType("struct.Child")), true); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Base")) - ->getFunction(0) - ->getName() - .str(), - "_ZN4Base3fooEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Base")) - ->getFunction(1) - ->getName() - .str(), - "_ZN4Base3barEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Child")) - ->getFunction(0) - ->getName() - .str(), - "_ZN5Child3fooEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Child")) - ->getFunction(1) - ->getName() - .str(), - "_ZN4Base3barEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Child")) - ->getFunction(2) - ->getName() - .str(), - "_ZN5Child3tarEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Base"))->size(), 2U); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Child"))->size(), 3U); + EXPECT_EQ(LTH.getSubTypes(LTH.getType("struct.Base")).size(), 2U); EXPECT_EQ(LTH.getSubTypes(LTH.getType("struct.Child")).size(), 1U); auto BaseReachable = LTH.getSubTypes(LTH.getType("struct.Base")); @@ -212,58 +123,7 @@ TEST(LTHTest, BasicTHReconstruction_5) { EXPECT_EQ(LTH.isSubType(LTH.getType("struct.OtherBase"), LTH.getType("struct.Child")), true); - EXPECT_EQ( - LTH.isSuperType(LTH.getType("struct.Child"), LTH.getType("struct.Base")), - true); - EXPECT_EQ(LTH.isSuperType(LTH.getType("struct.Child"), - LTH.getType("struct.OtherBase")), - true); - EXPECT_EQ(LTH.hasVFTable(LTH.getType("struct.Base")), true); - EXPECT_EQ(LTH.hasVFTable(LTH.getType("struct.OtherBase")), true); - EXPECT_EQ(LTH.hasVFTable(LTH.getType("struct.Child")), true); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Base")) - ->getFunction(0) - ->getName() - .str(), - "_ZN4Base3fooEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Base")) - ->getFunction(1) - ->getName() - .str(), - "_ZN4Base3barEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.OtherBase")) - ->getFunction(0) - ->getName() - .str(), - "_ZN9OtherBase3bazEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Child")) - ->getFunction(0) - ->getName() - .str(), - "_ZN5Child3fooEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Child")) - ->getFunction(1) - ->getName() - .str(), - "_ZN4Base3barEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Child")) - ->getFunction(2) - ->getName() - .str(), - "_ZN5Child3bazEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Child")) - ->getFunction(3) - ->getName() - .str(), - "_ZN5Child3tarEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Child")) - ->getFunction(4) - ->getName() - .str(), - "_ZThn8_N5Child3bazEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Base"))->size(), 2U); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.OtherBase"))->size(), 1U); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Child"))->size(), 5U); + EXPECT_EQ(LTH.getSubTypes(LTH.getType("struct.Base")).size(), 2U); EXPECT_EQ(LTH.getSubTypes(LTH.getType("struct.OtherBase")).size(), 2U); EXPECT_EQ(LTH.getSubTypes(LTH.getType("struct.Child")).size(), 1U); @@ -287,23 +147,7 @@ TEST(LTHTest, BasicTHReconstruction_6) { EXPECT_EQ( LTH.isSubType(LTH.getType("class.Base"), LTH.getType("struct.Child")), true); - EXPECT_EQ( - LTH.isSuperType(LTH.getType("struct.Child"), LTH.getType("class.Base")), - true); - EXPECT_EQ(LTH.hasVFTable(LTH.getType("class.Base")), true); - EXPECT_EQ(LTH.hasVFTable(LTH.getType("struct.Child")), true); - EXPECT_EQ(LTH.getVFTable(LTH.getType("class.Base")) - ->getFunction(0) - ->getName() - .str(), - "_ZN4Base3fooEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Child")) - ->getFunction(0) - ->getName() - .str(), - "_ZN5Child3fooEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("class.Base"))->size(), 1U); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Child"))->size(), 1U); + EXPECT_EQ(LTH.getSubTypes(LTH.getType("class.Base")).size(), 2U); EXPECT_EQ(LTH.getSubTypes(LTH.getType("struct.Child")).size(), 1U); auto BaseReachable = LTH.getSubTypes(LTH.getType("class.Base")); @@ -324,23 +168,7 @@ TEST(LTHTest, BasicTHReconstruction_7) { EXPECT_EQ( LTH.isSubType(LTH.getType("struct.Base"), LTH.getType("struct.Child")), true); - EXPECT_EQ( - LTH.isSuperType(LTH.getType("struct.Child"), LTH.getType("struct.Base")), - true); - EXPECT_EQ(LTH.hasVFTable(LTH.getType("struct.Base")), true); - EXPECT_EQ(LTH.hasVFTable(LTH.getType("struct.Child")), true); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Base")) - ->getFunction(0) - ->getName() - .str(), - "_ZN4Base3fooEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Child")) - ->getFunction(0) - ->getName() - .str(), - "_ZN5Child3fooEv"); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Base"))->size(), 1U); - EXPECT_EQ(LTH.getVFTable(LTH.getType("struct.Child"))->size(), 1U); + EXPECT_EQ(LTH.getSubTypes(LTH.getType("struct.Base")).size(), 2U); EXPECT_EQ(LTH.getSubTypes(LTH.getType("struct.Child")).size(), 1U); auto BaseReachable = LTH.getSubTypes(LTH.getType("struct.Base")); @@ -350,180 +178,6 @@ TEST(LTHTest, BasicTHReconstruction_7) { EXPECT_EQ(ChildReachable.count(LTH.getType("struct.Child")), true); } -// check if the vtables are constructed correctly in more complex scenarios -TEST(LTHTest, VTableConstruction) { - LLVMProjectIRDB IRDB1({unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_1_cpp.ll"}); - LLVMProjectIRDB IRDB2({unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_7_cpp.ll"}); - LLVMProjectIRDB IRDB3({unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_8_cpp.ll"}); - LLVMProjectIRDB IRDB4({unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_9_cpp.ll"}); - LLVMProjectIRDB IRDB5({unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_10_cpp.ll"}); - LLVMProjectIRDB IRDB6({unittest::PathToLLTestFiles + - "type_hierarchies/type_hierarchy_14_cpp.ll"}); - - // Creates an empty type hierarchy - LLVMTypeHierarchy TH1(IRDB1); - LLVMTypeHierarchy TH2(IRDB2); - LLVMTypeHierarchy TH3(IRDB3); - LLVMTypeHierarchy TH4(IRDB4); - LLVMTypeHierarchy TH5(IRDB5); - LLVMTypeHierarchy TH6(IRDB6); - - ASSERT_TRUE(TH1.hasVFTable(TH1.getType("struct.Base"))); - ASSERT_TRUE(TH1.hasVFTable(TH1.getType("struct.Child"))); - ASSERT_FALSE(TH1.hasVFTable(TH1.getType("struct.ANYTHING"))); - - ASSERT_TRUE(TH2.hasVFTable(TH2.getType("struct.A"))); - ASSERT_TRUE(TH2.hasVFTable(TH2.getType("struct.B"))); - ASSERT_TRUE(TH2.hasVFTable(TH2.getType("struct.C"))); - ASSERT_TRUE(TH2.hasVFTable(TH2.getType("struct.D"))); - ASSERT_TRUE(TH2.hasVFTable(TH2.getType("struct.X"))); - ASSERT_TRUE(TH2.hasVFTable(TH2.getType("struct.Y"))); - ASSERT_TRUE(TH2.hasVFTable(TH2.getType("struct.Z"))); - - ASSERT_TRUE(TH3.hasVFTable(TH3.getType("struct.Base"))); - ASSERT_TRUE(TH3.hasVFTable(TH3.getType("struct.Child"))); - ASSERT_FALSE(TH3.hasVFTable(TH3.getType("class.NonvirtualClass"))); - ASSERT_FALSE(TH3.hasVFTable(TH3.getType("struct.NonvirtualStruct"))); - - ASSERT_TRUE(TH4.hasVFTable(TH4.getType("struct.Base"))); - ASSERT_TRUE(TH4.hasVFTable(TH4.getType("struct.Child"))); - - ASSERT_TRUE(TH5.hasVFTable(TH5.getType("struct.Base"))); - ASSERT_TRUE(TH5.hasVFTable(TH5.getType("struct.Child"))); - - ASSERT_TRUE(demangle(TH1.getVFTable(TH1.getType("struct.Base")) - ->getFunction(0) - ->getName() - .str()) == "Base::foo()"); - ASSERT_TRUE(TH1.getVFTable(TH1.getType("struct.Base"))->size() == 1U); - ASSERT_TRUE(demangle(TH1.getVFTable(TH1.getType("struct.Child")) - ->getFunction(0) - ->getName() - .str()) == "Child::foo()"); - ASSERT_TRUE(TH1.getVFTable(TH1.getType("struct.Child"))->size() == 1U); - - ASSERT_TRUE(demangle(TH2.getVFTable(TH2.getType("struct.A")) - ->getFunction(0) - ->getName() - .str()) == "A::f()"); - ASSERT_TRUE(TH2.getVFTable(TH2.getType("struct.A"))->size() == 1U); - ASSERT_TRUE(demangle(TH2.getVFTable(TH2.getType("struct.B")) - ->getFunction(0) - ->getName() - .str()) == "A::f()"); - ASSERT_TRUE(TH2.getVFTable(TH2.getType("struct.B"))->size() == 1U); - ASSERT_TRUE(demangle(TH2.getVFTable(TH2.getType("struct.C")) - ->getFunction(0) - ->getName() - .str()) == "A::f()"); - ASSERT_TRUE( - - TH2.getVFTable(TH2.getType("struct.C"))->size() == 1U); - ASSERT_TRUE(demangle(TH2.getVFTable(TH2.getType("struct.D")) - ->getFunction(0) - ->getName() - .str()) == "A::f()"); - ASSERT_TRUE(TH2.getVFTable(TH2.getType("struct.D"))->size() == 1U); - ASSERT_TRUE(demangle(TH2.getVFTable(TH2.getType("struct.X")) - ->getFunction(0) - ->getName() - .str()) == "X::g()"); - ASSERT_TRUE( - - TH2.getVFTable(TH2.getType("struct.X"))->size() == 1U); - ASSERT_TRUE(demangle(TH2.getVFTable(TH2.getType("struct.Y")) - ->getFunction(0) - ->getName() - .str()) == "X::g()"); - ASSERT_TRUE( - - TH2.getVFTable(TH2.getType("struct.Y"))->size() == 1U); - ASSERT_TRUE(demangle(TH2.getVFTable(TH2.getType("struct.Z")) - ->getFunction(0) - ->getName() - .str()) == "A::f()"); - ASSERT_TRUE(demangle(TH2.getVFTable(TH2.getType("struct.Z")) - ->getFunction(1) - ->getName() - .str()) == "X::g()"); - ASSERT_TRUE(TH2.getVFTable(TH2.getType("struct.Z"))->size() == 2U); - - ASSERT_TRUE(demangle(TH3.getVFTable(TH3.getType("struct.Base")) - ->getFunction(0) - ->getName() - .str()) == "Base::foo()"); - ASSERT_TRUE(demangle(TH3.getVFTable(TH3.getType("struct.Base")) - ->getFunction(1) - ->getName() - .str()) == "Base::bar()"); - ASSERT_TRUE(TH3.getVFTable(TH3.getType("struct.Base"))->size() == 2U); - ASSERT_TRUE(demangle(TH3.getVFTable(TH3.getType("struct.Child")) - ->getFunction(0) - ->getName() - .str()) == "Child::foo()"); - ASSERT_TRUE(demangle(TH3.getVFTable(TH3.getType("struct.Child")) - ->getFunction(1) - ->getName() - .str()) == "Base::bar()"); - ASSERT_TRUE(demangle(TH3.getVFTable(TH3.getType("struct.Child")) - ->getFunction(2) - ->getName() - .str()) == "Child::baz()"); - ASSERT_TRUE(TH3.getVFTable(TH3.getType("struct.Child"))->size() == 3U); - - ASSERT_TRUE(demangle(TH4.getVFTable(TH4.getType("struct.Base")) - ->getFunction(0) - ->getName() - .str()) == "Base::foo()"); - ASSERT_TRUE(demangle(TH4.getVFTable(TH4.getType("struct.Base")) - ->getFunction(1) - ->getName() - .str()) == "Base::bar()"); - ASSERT_TRUE(TH4.getVFTable(TH4.getType("struct.Base"))->size() == 2U); - ASSERT_TRUE(demangle(TH4.getVFTable(TH4.getType("struct.Child")) - ->getFunction(0) - ->getName() - .str()) == "Child::foo()"); - ASSERT_TRUE(demangle(TH4.getVFTable(TH4.getType("struct.Child")) - ->getFunction(1) - ->getName() - .str()) == "Base::bar()"); - ASSERT_TRUE(demangle(TH4.getVFTable(TH4.getType("struct.Child")) - ->getFunction(2) - ->getName() - .str()) == "Child::baz()"); - ASSERT_TRUE(TH4.getVFTable(TH4.getType("struct.Child"))->size() == 3U); - - ASSERT_TRUE(demangle(TH5.getVFTable(TH5.getType("struct.Base")) - ->getFunction(0) - ->getName() - .str()) == "__cxa_pure_virtual"); - ASSERT_TRUE(demangle(TH5.getVFTable(TH5.getType("struct.Base")) - ->getFunction(1) - ->getName() - .str()) == "Base::bar()"); - ASSERT_TRUE(TH5.getVFTable(TH5.getType("struct.Base"))->size() == 2U); - ASSERT_TRUE(demangle(TH5.getVFTable(TH5.getType("struct.Child")) - ->getFunction(0) - ->getName() - .str()) == "Child::foo()"); - ASSERT_TRUE(demangle(TH5.getVFTable(TH5.getType("struct.Child")) - ->getFunction(1) - ->getName() - .str()) == "Base::bar()"); - ASSERT_TRUE(demangle(TH5.getVFTable(TH5.getType("struct.Child")) - ->getFunction(2) - ->getName() - .str()) == "Child::baz()"); - ASSERT_TRUE(TH5.getVFTable(TH5.getType("struct.Child"))->size() == 3U); - ASSERT_TRUE(TH6.getVFTable(TH6.getType("class.Base"))->size() == 3U); -} - TEST(LTHTest, TransitivelyReachableTypes) { LLVMProjectIRDB IRDB1({unittest::PathToLLTestFiles + "type_hierarchies/type_hierarchy_1_cpp.ll"}); @@ -752,13 +406,6 @@ PHASAR_SKIP_TEST(TEST(LTHTest, HandleSTLString) { TH.getType("class.std::__cxx11::basic_string"))); EXPECT_FALSE(TH.isSubType(TH.getType("union.anon"), TH.getType("class.std::__cxx11::basic_string"))); - EXPECT_FALSE(TH.isSuperType( - TH.getType("class.std::__cxx11::basic_string"), - TH.getType( - "struct.std::__cxx11::basic_string, " - "std::allocator >::_Alloc_hider"))); - EXPECT_TRUE(TH.isSuperType(TH.getType("class.std::allocator"), - TH.getType("class.std::allocator"))); }) } // namespace psr