source/FrameSet.h (161 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <initializer_list>
#include <ostream>
#include <json/json.h>
#include <AbstractDomain.h>
#include <PatriciaTreeMapAbstractPartition.h>
#include <mariana-trench/FlattenIterator.h>
#include <mariana-trench/Frame.h>
#include <mariana-trench/GroupHashedSetAbstractDomain.h>
namespace marianatrench {
/* Represents a set of frames with the same kind. */
class FrameSet final : public sparta::AbstractDomain<FrameSet> {
private:
using Set =
GroupHashedSetAbstractDomain<Frame, Frame::GroupHash, Frame::GroupEqual>;
using CallPositionToSetMap =
sparta::PatriciaTreeMapAbstractPartition<const Position*, Set>;
using CalleeToCallPositionToSetMap = sparta::
PatriciaTreeMapAbstractPartition<const Method*, CallPositionToSetMap>;
private:
// Iterator based on `FlattenIterator`.
struct CallPositionToSetMapDereference {
static Set::iterator begin(const std::pair<const Position*, Set>& pair) {
return pair.second.begin();
}
static Set::iterator end(const std::pair<const Position*, Set>& pair) {
return pair.second.end();
}
};
using CallPositionToSetMapIterator = FlattenIterator<
/* OuterIterator */ CallPositionToSetMap::MapType::iterator,
/* InnerIterator */ Set::iterator,
CallPositionToSetMapDereference>;
struct CalleeToCallPositionToSetMapDereference {
static CallPositionToSetMapIterator begin(
const std::pair<const Method*, CallPositionToSetMap>& pair) {
return CallPositionToSetMapIterator(
pair.second.bindings().begin(), pair.second.bindings().end());
}
static CallPositionToSetMapIterator end(
const std::pair<const Method*, CallPositionToSetMap>& pair) {
return CallPositionToSetMapIterator(
pair.second.bindings().end(), pair.second.bindings().end());
}
};
using ConstIterator = FlattenIterator<
/* OuterReference */ CalleeToCallPositionToSetMap::MapType::iterator,
/* InnerIterator */ CallPositionToSetMapIterator,
CalleeToCallPositionToSetMapDereference>;
public:
// C++ container concept member types
using iterator = ConstIterator;
using const_iterator = ConstIterator;
using value_type = Frame;
using difference_type = std::ptrdiff_t;
using size_type = std::size_t;
using const_reference = const Frame&;
using const_pointer = const Frame*;
private:
explicit FrameSet(
const Kind* MT_NULLABLE kind,
CalleeToCallPositionToSetMap map)
: kind_(kind), map_(std::move(map)) {}
public:
/* Create the bottom (i.e, empty) frame set. */
FrameSet() : kind_(nullptr), map_(CalleeToCallPositionToSetMap::bottom()) {}
explicit FrameSet(std::initializer_list<Frame> frames);
FrameSet(const FrameSet&) = default;
FrameSet(FrameSet&&) = default;
FrameSet& operator=(const FrameSet&) = default;
FrameSet& operator=(FrameSet&&) = default;
static FrameSet bottom() {
return FrameSet(/* kind */ nullptr, CalleeToCallPositionToSetMap::bottom());
}
static FrameSet top() {
return FrameSet(/* kind */ nullptr, CalleeToCallPositionToSetMap::top());
}
bool is_bottom() const override {
return map_.is_bottom();
}
bool is_top() const override {
return map_.is_top();
}
void set_to_bottom() override {
kind_ = nullptr;
map_.set_to_bottom();
}
void set_to_top() override {
kind_ = nullptr;
map_.set_to_top();
}
bool empty() const {
return map_.is_bottom();
}
const Kind* MT_NULLABLE kind() const {
return kind_;
}
bool is_artificial_sources() const {
return kind_ == Kinds::artificial_source();
}
void add(const Frame& frame);
bool leq(const FrameSet& other) const override;
bool equals(const FrameSet& other) const override;
void join_with(const FrameSet& other) override;
void widen_with(const FrameSet& other) override;
void meet_with(const FrameSet& other) override;
void narrow_with(const FrameSet& other) override;
void difference_with(const FrameSet& other);
void map(const std::function<void(Frame&)>& f);
void filter(const std::function<bool(const Frame&)>& predicate);
ConstIterator begin() const {
return ConstIterator(map_.bindings().begin(), map_.bindings().end());
}
ConstIterator end() const {
return ConstIterator(map_.bindings().end(), map_.bindings().end());
}
void add_inferred_features(const FeatureMayAlwaysSet& features);
LocalPositionSet local_positions() const;
void add_local_position(const Position* position);
void set_local_positions(const LocalPositionSet& positions);
void add_inferred_features_and_local_position(
const FeatureMayAlwaysSet& features,
const Position* MT_NULLABLE position);
/**
* Propagate the taint from the callee to the caller.
*
* Return bottom if the taint should not be propagated.
*/
FrameSet propagate(
const Method* caller,
const Method* callee,
const AccessPath& callee_port,
const Position* call_position,
int maximum_source_sink_distance,
Context& context,
const std::vector<const DexType * MT_NULLABLE>& source_register_types,
const std::vector<std::optional<std::string>>& source_constant_arguments)
const;
/* Return the set of leaf frames with the given position. */
FrameSet attach_position(const Position* position) const;
/**
* Convert the kind of these frames into the given kind.
*
* Return A new FrameSet, identical in everyway except in "kind".
*/
FrameSet with_kind(const Kind* kind) const;
template <class T>
std::unordered_map<T, std::vector<std::reference_wrapper<const Frame>>>
partition_map(const std::function<T(const Frame&)>& map) const;
static FrameSet from_json(const Json::Value& value, Context& context);
Json::Value to_json() const;
friend std::ostream& operator<<(std::ostream& out, const FrameSet& frames);
private:
Frame propagate_frames(
const Method* callee,
const AccessPath& callee_port,
const Position* call_position,
int maximum_source_sink_distance,
Context& context,
const std::vector<const DexType * MT_NULLABLE>& source_register_types,
const std::vector<std::optional<std::string>>& source_constant_arguments,
std::vector<std::reference_wrapper<const Frame>> frames,
std::vector<const Feature*>& via_type_of_features_added) const;
FrameSet propagate_crtex_frames(
const Method* callee,
const AccessPath& callee_port,
const Position* call_position,
int maximum_source_sink_distance,
Context& context,
const std::vector<const DexType * MT_NULLABLE>& source_register_types,
std::vector<std::reference_wrapper<const Frame>> frames) const;
private:
const Kind* MT_NULLABLE kind_;
CalleeToCallPositionToSetMap map_;
};
} // namespace marianatrench