source/model-generator/ModelGenerator.h (193 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 <optional>
#include <string>
#include <DexClass.h>
#include <DexUtil.h>
#include <RedexResources.h>
#include <Walkers.h>
#include <mariana-trench/Context.h>
#include <mariana-trench/FieldModel.h>
#include <mariana-trench/Frame.h>
#include <mariana-trench/MethodSet.h>
#include <mariana-trench/Methods.h>
#include <mariana-trench/Model.h>
#include <mariana-trench/Options.h>
#include <mariana-trench/Overrides.h>
namespace marianatrench {
using MethodHashedSet = sparta::HashedSetAbstractDomain<const Method*>;
struct MethodMappings {
explicit MethodMappings(const Methods& methods);
ConcurrentMap<std::string, MethodHashedSet> name_to_methods;
ConcurrentMap<std::string, MethodHashedSet> class_to_methods;
ConcurrentMap<std::string, MethodHashedSet> class_to_override_methods;
ConcurrentMap<std::string, MethodHashedSet> signature_to_methods;
MethodHashedSet all_methods;
};
struct ModelGeneratorResult {
std::vector<Model> method_models;
std::vector<FieldModel> field_models;
};
class ModelGenerator {
public:
ModelGenerator(const std::string& name, Context& context);
ModelGenerator(const ModelGenerator&) = delete;
ModelGenerator(ModelGenerator&&) = default;
ModelGenerator& operator=(const ModelGenerator&) = delete;
ModelGenerator& operator=(ModelGenerator&&) = delete;
virtual ~ModelGenerator() = default;
virtual const std::string& name() const {
return name_;
}
virtual std::vector<Model> emit_method_models(const Methods& /* methods */) {
return {};
}
virtual std::vector<Model> emit_method_models_optimized(
const Methods& methods,
const MethodMappings& method_mappings);
virtual std::vector<FieldModel> emit_field_models(
const Fields& /* fields */) {
return {};
}
ModelGeneratorResult run(const Methods& methods, const Fields& fields);
ModelGeneratorResult run_optimized(
const Methods& methods,
const MethodMappings& method_mappings,
const Fields& fields);
protected:
std::string name_;
Context& context_;
const Options& options_;
const Methods& methods_;
const Overrides& overrides_;
};
class MethodVisitorModelGenerator : public ModelGenerator {
public:
MethodVisitorModelGenerator(const std::string& name, Context& context)
: ModelGenerator(name, context) {}
virtual std::vector<Model> emit_method_models(const Methods&) override;
// This method has to be thread-safe.
virtual std::vector<Model> visit_method(const Method* method) const = 0;
protected:
template <typename InputIt>
std::vector<Model> run_impl(InputIt begin, InputIt end) {
std::vector<Model> models;
std::mutex mutex;
auto queue = sparta::work_queue<const Method*>([&](const Method* method) {
std::vector<Model> method_models = this->visit_method(method);
if (!method_models.empty()) {
std::lock_guard<std::mutex> lock(mutex);
models.insert(
models.end(),
std::make_move_iterator(method_models.begin()),
std::make_move_iterator(method_models.end()));
}
});
for (auto iterator = begin; iterator != end; ++iterator) {
queue.add_item(*iterator);
}
queue.run_all();
return models;
}
};
class FieldVisitorModelGenerator : public ModelGenerator {
public:
FieldVisitorModelGenerator(const std::string& name, Context& context)
: ModelGenerator(name, context) {}
virtual std::vector<FieldModel> emit_field_models(const Fields&) override;
// This method has to be thread-safe.
virtual std::vector<FieldModel> visit_field(const Field* field) const = 0;
protected:
template <typename InputIt>
std::vector<FieldModel> run_impl(InputIt begin, InputIt end) {
std::vector<FieldModel> models;
std::mutex mutex;
auto queue = sparta::work_queue<const Field*>([&](const Field* field) {
auto field_models = this->visit_field(field);
if (!field_models.empty()) {
std::lock_guard<std::mutex> lock(mutex);
models.insert(
models.end(),
std::make_move_iterator(field_models.begin()),
std::make_move_iterator(field_models.end()));
}
});
for (auto iterator = begin; iterator != end; ++iterator) {
queue.add_item(*iterator);
}
queue.run_all();
return models;
}
};
namespace generator {
const std::string& get_class_name(const Method* method);
const std::string& get_method_name(const Method* method);
std::optional<std::string> get_super_type(const Method* method);
std::optional<const DexType*> get_return_type(const Method* method);
std::optional<std::string> get_return_type_string(const Method* method);
std::unordered_set<std::string> get_interfaces_from_class(DexClass* dex_class);
std::unordered_set<std::string> get_parents_from_class(
DexClass* dex_class,
bool include_interfaces);
std::unordered_set<std::string> get_custom_parents_from_class(
DexClass* dex_class);
std::string get_outer_class(const std::string& classname);
bool is_numeric_data_type(const DataType& type);
std::vector<std::pair<ParameterPosition, const DexType*>> get_argument_types(
const DexMethod* dex_method);
std::vector<std::pair<ParameterPosition, const DexType*>> get_argument_types(
const Method* method);
std::vector<std::pair<ParameterPosition, std::string>>
get_argument_types_string(const Method* method);
void add_propagation_to_return(
Context& context,
Model& model,
ParameterPosition parameter_position,
const std::vector<std::string>& features = {});
void add_propagation_to_parameter(
Context& context,
Model& model,
ParameterPosition from,
ParameterPosition to,
const std::vector<std::string>& features = {});
void add_propagation_to_self(
Context& context,
Model& model,
ParameterPosition parameter_position,
const std::vector<std::string>& features = {});
/* Checks whether the given method is annotated with the given annotation type
* and value. */
bool has_annotation(
const DexMethod* method,
const std::string& expected_type,
const std::optional<std::unordered_set<std::string>>& expected_values =
std::nullopt);
/* Checks whether the given class is annotated with the given annotation type
* and value. */
bool has_annotation(
const DexClass* dex_class,
const std::string& expected_type,
const std::optional<std::unordered_set<std::string>>& expected_values =
std::nullopt);
Frame source(
Context& context,
const Method* method,
const std::string& kind,
const std::vector<std::string>& features = {},
Root::Kind callee_port = Root::Kind::Leaf,
RootSetAbstractDomain via_type_of_ports = {},
RootSetAbstractDomain via_value_of_ports = {});
Frame sink(
Context& context,
const Method* method,
const std::string& kind,
const std::vector<std::string>& features = {},
Root::Kind callee_port = Root::Kind::Leaf,
RootSetAbstractDomain via_type_of_ports = {},
RootSetAbstractDomain via_value_of_ports = {},
CanonicalNameSetAbstractDomain canonical_names =
CanonicalNameSetAbstractDomain{});
Frame partial_sink(
Context& context,
const Method* method,
const std::string& kind,
const std::string& label,
const std::vector<std::string>& features = {},
Root::Kind callee_port = Root::Kind::Leaf,
RootSetAbstractDomain via_type_of_ports = {},
RootSetAbstractDomain via_value_of_ports = {});
} // namespace generator
} // namespace marianatrench