Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Filtered AliasSet #723

Open
wants to merge 10 commits into
base: development
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ class IFDSTaintAnalysis
const llvm::Function *Callee) const;

void populateWithMayAliases(container_type &Facts,
const llvm::Instruction *Context) const;
const llvm::Instruction *AliasQueryInst) const;
void populateWithMustAliases(container_type &Facts,
const llvm::Instruction *Context) const;
const llvm::Instruction *AliasQueryInst) const;
};
} // namespace psr

Expand Down
154 changes: 154 additions & 0 deletions include/phasar/PhasarLLVM/Pointer/FilteredLLVMAliasSet.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/******************************************************************************
* Copyright (c) 2020 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_POINTER_FILTEREDLLVMALIASSET_H
#define PHASAR_PHASARLLVM_POINTER_FILTEREDLLVMALIASSET_H

#include "phasar/Pointer/AliasAnalysisType.h"
#include "phasar/Pointer/AliasInfoTraits.h"
#include "phasar/Pointer/AliasResult.h"
#include "phasar/Pointer/AliasSetOwner.h"
#include "phasar/Utils/AnalysisProperties.h"
#include "phasar/Utils/MaybeUniquePtr.h"

#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/ErrorHandling.h"

#include "nlohmann/json_fwd.hpp"

#include <type_traits>
#include <utility>

namespace llvm {
class Value;
class Instruction;
} // namespace llvm

namespace psr {

class LLVMAliasSet;
class FilteredLLVMAliasSet;

template <>
struct AliasInfoTraits<FilteredLLVMAliasSet>
: DefaultAATraits<const llvm::Value *, const llvm::Instruction *> {};

class FilteredLLVMAliasSet {
public:
using alias_traits_t = AliasInfoTraits<FilteredLLVMAliasSet>;
using n_t = alias_traits_t::n_t;
using v_t = alias_traits_t::v_t;
using AliasSetTy = alias_traits_t::AliasSetTy;
using AliasSetPtrTy = alias_traits_t::AliasSetPtrTy;
using AllocationSiteSetPtrTy = alias_traits_t::AllocationSiteSetPtrTy;

FilteredLLVMAliasSet(LLVMAliasSet *AS) noexcept;

FilteredLLVMAliasSet(const FilteredLLVMAliasSet &) = delete;
FilteredLLVMAliasSet &operator=(const FilteredLLVMAliasSet &) = delete;
FilteredLLVMAliasSet &operator=(FilteredLLVMAliasSet &&) noexcept = delete;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

FilteredLLVMAliasSet(FilteredLLVMAliasSet &&) noexcept = default;

~FilteredLLVMAliasSet();

template <typename... ArgsT,
typename = std::enable_if_t<
std::is_constructible_v<LLVMAliasSet, ArgsT...>>>
explicit FilteredLLVMAliasSet(ArgsT &&...Args)
: FilteredLLVMAliasSet(std::forward<ArgsT>(Args)...) {}

// --- API Functions:

[[nodiscard]] inline bool isInterProcedural() const noexcept {
return false;
};

[[nodiscard]] AliasAnalysisType getAliasAnalysisType() const noexcept;

[[nodiscard]] AliasResult alias(const llvm::Value *V1, const llvm::Value *V2,
const llvm::Instruction *I);
[[nodiscard]] AliasResult alias(const llvm::Value *V1, const llvm::Value *V2,
const llvm::Function *Fun);

[[nodiscard]] AliasSetPtrTy getAliasSet(const llvm::Value *V,
const llvm::Instruction *I);
[[nodiscard]] AliasSetPtrTy getAliasSet(const llvm::Value *V,
const llvm::Function *Fun);

[[nodiscard]] AllocationSiteSetPtrTy
getReachableAllocationSites(const llvm::Value *V, bool IntraProcOnly = false,
const llvm::Instruction *I = nullptr);

// Checks if PotentialValue is in the reachable allocation sites of V.
[[nodiscard]] bool isInReachableAllocationSites(
const llvm::Value *V, const llvm::Value *PotentialValue,
bool IntraProcOnly = false, const llvm::Instruction *I = nullptr);

void mergeWith(const FilteredLLVMAliasSet & /*OtherPTI*/) {
llvm::report_fatal_error("Not Supported");
}

void introduceAlias(const llvm::Value * /*V1*/, const llvm::Value * /*V2*/,
const llvm::Instruction * /*I*/ = nullptr,
AliasResult /*Kind*/ = AliasResult::MustAlias) {
llvm::report_fatal_error("Not Supported");
}

void print(llvm::raw_ostream &OS = llvm::outs()) const;

[[nodiscard]] nlohmann::json getAsJson() const;

void printAsJson(llvm::raw_ostream &OS = llvm::outs()) const;

[[nodiscard]] AnalysisProperties getAnalysisProperties() const noexcept {
return AnalysisProperties::None;
}

private:
struct ReachableAllocationSitesKey {
llvm::PointerIntPair<const llvm::Function *, 1, bool> FunAndIntraProcOnly;
v_t Value{};
};

struct ReachableAllocationSitesKeyDMI {
inline static ReachableAllocationSitesKey getEmptyKey() noexcept {
return {{}, llvm::DenseMapInfo<v_t>::getEmptyKey()};
}
inline static ReachableAllocationSitesKey getTombstoneKey() noexcept {
return {{}, llvm::DenseMapInfo<v_t>::getTombstoneKey()};
}
inline static auto getHashValue(ReachableAllocationSitesKey Key) noexcept {
return llvm::hash_combine(Key.FunAndIntraProcOnly.getOpaqueValue(),
Key.Value);
}
inline static bool isEqual(ReachableAllocationSitesKey Key1,
ReachableAllocationSitesKey Key2) noexcept {
return Key1.FunAndIntraProcOnly == Key2.FunAndIntraProcOnly &&
Key1.Value == Key2.Value;
}
};

FilteredLLVMAliasSet(MaybeUniquePtr<LLVMAliasSet, true> AS) noexcept;

MaybeUniquePtr<LLVMAliasSet, /*RequireAlignment=*/true> AS;
AliasSetOwner<AliasSetTy> Owner;
llvm::DenseMap<std::pair<const llvm::Function *, v_t>, AliasSetPtrTy>
AliasSetMap;
llvm::DenseMap<ReachableAllocationSitesKey, std::unique_ptr<AliasSetTy>,
ReachableAllocationSitesKeyDMI>
ReachableAllocationSitesMap;
};
} // namespace psr

#endif // PHASAR_PHASARLLVM_POINTER_FILTEREDLLVMALIASSET_H
2 changes: 2 additions & 0 deletions include/phasar/PhasarLLVM/Pointer/LLVMAliasSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ struct AliasInfoTraits<LLVMAliasSet>

class LLVMAliasSet : public AnalysisPropertiesMixin<LLVMAliasSet>,
public AliasInfoBaseUtils {
// For int*IsReachableAllocationSiteTy:
friend class FilteredLLVMAliasSet;

public:
using traits_t = AliasInfoTraits<LLVMAliasSet>;
Expand Down
5 changes: 2 additions & 3 deletions include/phasar/Pointer/AliasInfoTraits.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@
#define PHASAR_POINTER_ALIASINFOTRAITS_H

#include "phasar/Utils/BoxedPointer.h"
#include "phasar/Utils/MaybeUniquePtr.h"

#include "llvm/ADT/DenseSet.h"

#include <memory>

namespace psr {

template <typename T> struct AliasInfoTraits {
Expand All @@ -31,7 +30,7 @@ template <typename V, typename N> struct DefaultAATraits {
using v_t = V;
using AliasSetTy = llvm::DenseSet<v_t>;
using AliasSetPtrTy = BoxedConstPtr<AliasSetTy>;
using AllocationSiteSetPtrTy = std::unique_ptr<AliasSetTy>;
using AllocationSiteSetPtrTy = MaybeUniquePtr<const AliasSetTy>;
};
} // namespace psr

Expand Down
8 changes: 5 additions & 3 deletions include/phasar/Utils/MaybeUniquePtr.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ template <typename T> class MaybeUniquePtrBase<T, true> {
/// \tparam RequireAlignment If true, the datastructure only works if
/// alignof(T) > 1 holds. Enables incomplete T types
template <typename T, bool RequireAlignment = false>
class MaybeUniquePtr : detail::MaybeUniquePtrBase<T, RequireAlignment> {
class [[clang::trivial_abi]] MaybeUniquePtr
: detail::MaybeUniquePtrBase<T, RequireAlignment> {
using detail::MaybeUniquePtrBase<T, RequireAlignment>::Data;

public:
Expand All @@ -79,8 +80,9 @@ class MaybeUniquePtr : detail::MaybeUniquePtrBase<T, RequireAlignment> {
: MaybeUniquePtr(Owner.release(), true) {}

constexpr MaybeUniquePtr(MaybeUniquePtr &&Other) noexcept
: detail::MaybeUniquePtrBase<T, RequireAlignment>(
std::exchange(Other.Data, {})) {}
: detail::MaybeUniquePtrBase<T, RequireAlignment>(std::move(Other)) {
Other.Data = {};
}

constexpr void swap(MaybeUniquePtr &Other) noexcept {
std::swap(Data, Other.Data);
Expand Down
21 changes: 11 additions & 10 deletions lib/PhasarLLVM/DataFlow/IfdsIde/Problems/IFDSTaintAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,16 +116,17 @@ bool IFDSTaintAnalysis::isSanitizerCall(const llvm::CallBase * /*CB*/,
[this](const auto &Arg) { return Config->isSanitizer(&Arg); });
}

static bool canSkipAtContext(const llvm::Value *Val,
const llvm::Instruction *Context) noexcept {
static bool
canSkipAtQueryInst(const llvm::Value *Val,
const llvm::Instruction *AliasQueryInst) noexcept {
if (const auto *Inst = llvm::dyn_cast<llvm::Instruction>(Val)) {
/// Mapping instructions between functions is done via the call-FF and
/// ret-FF
if (Inst->getFunction() != Context->getFunction()) {
if (Inst->getFunction() != AliasQueryInst->getFunction()) {
return true;
}
if (Inst->getParent() == Context->getParent() &&
Context->comesBefore(Inst)) {
if (Inst->getParent() == AliasQueryInst->getParent() &&
AliasQueryInst->comesBefore(Inst)) {
// We will see that inst later
return true;
}
Expand All @@ -134,7 +135,7 @@ static bool canSkipAtContext(const llvm::Value *Val,

if (const auto *Arg = llvm::dyn_cast<llvm::Argument>(Val)) {
// An argument is only valid in the function it belongs to
if (Arg->getParent() != Context->getFunction()) {
if (Arg->getParent() != AliasQueryInst->getFunction()) {
return true;
}
}
Expand All @@ -151,12 +152,12 @@ static bool isCompiletimeConstantData(const llvm::Value *Val) noexcept {
}

void IFDSTaintAnalysis::populateWithMayAliases(
container_type &Facts, const llvm::Instruction *Context) const {
container_type &Facts, const llvm::Instruction *AliasQueryInst) const {
container_type Tmp = Facts;
for (const auto *Fact : Facts) {
auto Aliases = PT.getAliasSet(Fact);
auto Aliases = PT.getAliasSet(Fact, AliasQueryInst);
for (const auto *Alias : *Aliases) {
if (canSkipAtContext(Alias, Context)) {
if (canSkipAtQueryInst(Alias, AliasQueryInst)) {
continue;
}

Expand All @@ -178,7 +179,7 @@ void IFDSTaintAnalysis::populateWithMayAliases(
}

void IFDSTaintAnalysis::populateWithMustAliases(
container_type &Facts, const llvm::Instruction *Context) const {
container_type &Facts, const llvm::Instruction *AliasQueryInst) const {
/// TODO: Find must-aliases; Currently the AliasSet only contains
/// may-aliases
}
Expand Down
Loading