-
Notifications
You must be signed in to change notification settings - Fork 139
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
Repeating life cycles #168
Repeating life cycles #168
Conversation
ZeyadTarekk
commented
Aug 7, 2024
- The current syntax only allows the generation of a succession of method calls.
- We have changed the design slightly, we now want the user to provide a control flow graph structure.
source/LifecycleMethod.h
Outdated
} | ||
}; | ||
|
||
std::unordered_map<LifecycleMethodCall, std::vector<LifecycleMethodCall>, NodeHasher> adj_list_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This representation doesn't seem quite right. Why is the key a MethodCall itself? I thought we said it should be the name used as the key in the json. It should just be a string.
The parsing logic is quite weird, since we seem to create one node for each call, but a node is a std::vector
. Basically, you are never using vectors of more than 1 element.
I think this should be redesigned to be something like:
std::unordered_map<std::stringg, LifecycleGraphNode> nodes_
And LifecycleGraphNode
should have a std::vector<LifecycleMethodCall>
has well as a std::vector<std::string> successors
.
source/LifecycleMethod.h
Outdated
@@ -174,7 +201,7 @@ class LifecycleMethod { | |||
|
|||
std::string base_class_name_; | |||
std::string method_name_; | |||
std::vector<LifecycleMethodCall> callees_; | |||
std::variant<std::vector<LifecycleMethodCall>,LifeCycleMethodGraph> callees_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe rename this as body_
since this represents the method body (i.e content).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^ rename this body_
as said before.
source/LifecycleMethod.cpp
Outdated
for (const auto& callee : callees_) { | ||
auto* dex_method = callee.get_dex_method(dex_klass); | ||
if (!dex_method) { | ||
// Dex method does not apply for current APK. | ||
// See `LifecycleMethod::validate()`. | ||
continue; | ||
} | ||
|
||
++callee_count; | ||
|
||
std::vector<Location> invoke_with_registers{this_location}; | ||
auto* type_list = callee.get_argument_types(); | ||
// This should have been verified at the start of `create_methods` | ||
mt_assert(type_list != nullptr); | ||
for (auto* type : *type_list) { | ||
auto argument_register = method.get_local(type_index_map.at(type)); | ||
invoke_with_registers.push_back(argument_register); | ||
} | ||
main_block->invoke( | ||
IROpcode::OPCODE_INVOKE_VIRTUAL, dex_method, invoke_with_registers); | ||
} | ||
// for (const auto& callee : callees_) { | ||
// auto* dex_method = callee.get_dex_method(dex_klass); | ||
// if (!dex_method) { | ||
// // Dex method does not apply for current APK. | ||
// // See `LifecycleMethod::validate()`. | ||
// continue; | ||
// } | ||
|
||
// ++callee_count; | ||
|
||
// std::vector<Location> invoke_with_registers{this_location}; | ||
// auto* type_list = callee.get_argument_types(); | ||
// // This should have been verified at the start of `create_methods` | ||
// mt_assert(type_list != nullptr); | ||
// for (auto* type : *type_list) { | ||
// auto argument_register = method.get_local(type_index_map.at(type)); | ||
// invoke_with_registers.push_back(argument_register); | ||
// } | ||
// main_block->invoke( | ||
// IROpcode::OPCODE_INVOKE_VIRTUAL, dex_method, invoke_with_registers); | ||
// } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Obviously, we will need to keep this from now otherwise this will break existing lifecycle configurations.
source/LifecycleMethod.h
Outdated
const std::vector<std::string>& successors() const; | ||
bool operator==(const LifecycleGraphNode& other) const; | ||
|
||
INCLUDE_DEFAULT_COPY_CONSTRUCTORS_AND_ASSIGNMENTS(LifecycleGraphNode) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for consistency with the rest of our codebase, please move this right after the constructor
source/LifecycleMethod.h
Outdated
const std::vector<LifecycleMethodCall>& method_calls() const; | ||
const std::vector<std::string>& successors() const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: inline these since the implementation is really small
can we inline the implementation of these, since those should be small?
const std::vector<LifecycleMethodCall>& method_calls() const; | |
const std::vector<std::string>& successors() const; | |
const std::vector<LifecycleMethodCall>& method_calls() const { return method_calls_; } | |
const std::vector<std::string>& successors() const { return successors_; } |
source/LifecycleMethod.h
Outdated
void addNode(const std::string& node_name,std::vector<LifecycleMethodCall> method_calls,std::vector<std::string> successors); | ||
|
||
const LifecycleGraphNode* getNode(const std::string& node_name) const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: we use snake_case for method names, so it should be add_node
and get_node
.
source/LifecycleMethod.h
Outdated
@@ -174,7 +201,7 @@ class LifecycleMethod { | |||
|
|||
std::string base_class_name_; | |||
std::string method_name_; | |||
std::vector<LifecycleMethodCall> callees_; | |||
std::variant<std::vector<LifecycleMethodCall>,LifeCycleMethodGraph> callees_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^ rename this body_
as said before.
source/LifecycleMethod.cpp
Outdated
if (nodes_.size() != other.nodes_.size()) { | ||
return false; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not really necessary, nodes_ == other.nodes_
will do the same check.
source/LifecycleMethod.cpp
Outdated
JsonValidation::validate_object(node, "node"); | ||
const auto& instructions = node["instructions"]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think those are not necessary anymore?
source/LifecycleMethod.cpp
Outdated
for (const auto& callee : JsonValidation::null_or_array(value, "callees")) { | ||
callees.push_back(LifecycleMethodCall::from_json(callee)); | ||
} | ||
return LifecycleMethod(base_class_name, method_name, callees); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: std::move
return LifecycleMethod(base_class_name, method_name, callees); | |
return LifecycleMethod(base_class_name, method_name, std::move(callees)); |
source/LifecycleMethod.cpp
Outdated
} else if (JsonValidation::has_field(value, "control_flow_graph")) { | ||
JsonValidation::validate_object(value, "control_flow_graph"); | ||
LifeCycleMethodGraph graph = LifeCycleMethodGraph::from_json(JsonValidation::object(value, "control_flow_graph")); | ||
return LifecycleMethod(base_class_name, method_name, graph); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also here
return LifecycleMethod(base_class_name, method_name, graph); | |
return LifecycleMethod(base_class_name, method_name, std::move(graph)); |
source/LifecycleMethod.cpp
Outdated
} | ||
|
||
return LifecycleMethod(base_class_name, method_name, callees); | ||
throw std::invalid_argument("Invalid JSON format for LifecycleMethod"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's be a bit more descriptive, otherwise this will be confusing to the user.
We should also use JsonValidationError.
throw std::invalid_argument("Invalid JSON format for LifecycleMethod"); | |
throw JsonValidationError( | |
value, | |
/* field */ std::nullopt, | |
"key `callees` or `control_flow_graph`"); |
source/LifecycleMethod.cpp
Outdated
// for (const auto& callee : callees_) { | ||
// callee.validate(base_class, class_hierarchies); | ||
// } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This still needs to be addressed. And same thing below.
You can do something like:
if (const auto* callees = std::get_if<std::vector<LifecycleMethodCall>>(callees_)) {
// handle *callees
} else {
const auto& graph = std::get< LifeCycleMethodGraph>(callees_);
// handle graph
}
Could we also add tests, as I suggested last week? |
for (const auto& callee : *callees) { | ||
auto* dex_method = callee.get_dex_method(dex_klass); | ||
if (!dex_method) { | ||
// Dex method does not apply for current APK. | ||
// See `LifecycleMethod::validate()`. | ||
continue; | ||
} | ||
|
||
++callee_count; | ||
|
||
std::vector<Location> invoke_with_registers{this_location}; | ||
auto* type_list = callee.get_argument_types(); | ||
// This should have been verified at the start of `create_methods` | ||
mt_assert(type_list != nullptr); | ||
for (auto* type : *type_list) { | ||
auto argument_register = method.get_local(type_index_map.at(type)); | ||
invoke_with_registers.push_back(argument_register); | ||
std::vector<Location> invoke_with_registers{this_location}; | ||
auto* type_list = callee.get_argument_types(); | ||
// This should have been verified at the start of `create_methods` | ||
mt_assert(type_list != nullptr); | ||
for (auto* type : *type_list) { | ||
auto argument_register = method.get_local(type_index_map.at(type)); | ||
invoke_with_registers.push_back(argument_register); | ||
} | ||
main_block->invoke( | ||
IROpcode::OPCODE_INVOKE_VIRTUAL, dex_method, invoke_with_registers); | ||
} | ||
main_block->invoke( | ||
IROpcode::OPCODE_INVOKE_VIRTUAL, dex_method, invoke_with_registers); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe move these in a function generate_invoke_instructions
that take a list of LifecycleMethodCall
and the main_block
. This will be useful for the next step.
source/LifecycleMethod.cpp
Outdated
for (const auto& callee : callees_) { | ||
callee.validate(base_class, class_hierarchies); | ||
if (const auto* callees = std::get_if<std::vector<LifecycleMethodCall>>(&body_)) { | ||
// handle *callees |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: remove this comment
source/LifecycleMethod.h
Outdated
@@ -53,6 +53,8 @@ class LifecycleMethodCall { | |||
|
|||
static LifecycleMethodCall from_json(const Json::Value& value); | |||
|
|||
const std::string get_method_name() const { return method_name_; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing & here
const std::string get_method_name() const { return method_name_; } | |
const std::string& get_method_name() const { return method_name_; } |
@arthaud has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |