Skip to content

Commit 5566351

Browse files
committed
implement --dump-unresolved-methods option
1 parent 37a0b24 commit 5566351

15 files changed

+75
-5
lines changed

shim/shim.py

+7
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,11 @@ def _add_debug_arguments(parser: argparse.ArgumentParser) -> None:
585585
action="store_true",
586586
help="Dump the call graph in `call_graph.json`.",
587587
)
588+
debug_arguments.add_argument(
589+
"--dump-unresolved-methods",
590+
action="store_true",
591+
help="Dump the list of unresolved methods in `unresolved_methods.json`.",
592+
)
588593
debug_arguments.add_argument(
589594
"--dump-dependencies",
590595
action="store_true",
@@ -737,6 +742,8 @@ def _get_command_options(
737742
options.append("--dump-overrides")
738743
if arguments.dump_call_graph:
739744
options.append("--dump-call-graph")
745+
if arguments.dump_unresolved_methods:
746+
options.append("--dump-unresolved-methods")
740747
if arguments.dump_dependencies:
741748
options.append("--dump-dependencies")
742749
if arguments.dump_methods:

source/BackwardTaintTransfer.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,8 @@ bool BackwardTaintTransfer::analyze_invoke(
733733
aliasing.position(),
734734
get_source_register_types(context, instruction),
735735
source_constant_arguments,
736-
get_is_this_call(aliasing.register_memory_locations_map(), instruction));
736+
get_is_this_call(aliasing.register_memory_locations_map(), instruction),
737+
context->statistics);
737738

738739
TaintTree result_taint = TaintTree::bottom();
739740
if (callee.resolved_base_method &&

source/ForwardAliasTransfer.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,8 @@ MemoryLocationsDomain invoke_result_memory_location(
135135
environment->last_position(),
136136
get_source_register_types(context, instruction),
137137
get_source_constant_arguments(register_memory_locations_map, instruction),
138-
get_is_this_call(register_memory_locations_map, instruction));
138+
get_is_this_call(register_memory_locations_map, instruction),
139+
context->statistics);
139140

140141
if (callee.resolved_base_method &&
141142
callee.resolved_base_method->returns_void()) {

source/ForwardTaintTransfer.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -910,7 +910,8 @@ bool ForwardTaintTransfer::analyze_invoke(
910910
aliasing.position(),
911911
get_source_register_types(context, instruction),
912912
source_constant_arguments,
913-
get_is_this_call(aliasing.register_memory_locations_map(), instruction));
913+
get_is_this_call(aliasing.register_memory_locations_map(), instruction),
914+
context->statistics);
914915

915916
const ForwardTaintEnvironment previous_environment = *environment;
916917

source/MarianaTrench.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,18 @@ void MarianaTrench::run(const program_options::variables_map& variables) {
484484
rule_coverage_timer.duration_in_seconds());
485485
}
486486

487+
if (options.dump_unresolved_methods()) {
488+
Timer dump_unresolved_methods_timer;
489+
auto unresolved_methods_output_path = options.unresolved_methods_output_path();
490+
LOG(1, "Writing unresolved methods to `{}`.", unresolved_methods_output_path.native());
491+
registry.dump_unresolved_methods(unresolved_methods_output_path);
492+
context.statistics->log_time(
493+
"dump_unresolved_methods", dump_unresolved_methods_timer);
494+
LOG(1,
495+
"Wrote unresolved methods list in {:.2f}s.",
496+
dump_unresolved_methods_timer.duration_in_seconds());
497+
}
498+
487499
auto metadata_path = options.metadata_output_path();
488500
LOG(1, "Writing metadata to `{}`.", metadata_path.native());
489501
registry.dump_metadata(/* path */ metadata_path);

source/MethodContext.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ MethodContext::MethodContext(
4444
memory_factory(previous_model.method()),
4545
previous_model(previous_model),
4646
new_model(new_model),
47+
statistics(*context.statistics),
4748
context_(context),
4849
dump_(previous_model.method()->should_be_logged(options)) {}
4950

source/MethodContext.h

+1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ class MethodContext final {
8888
FulfilledPartialKindResults fulfilled_partial_sinks;
8989
const Model& previous_model;
9090
Model& new_model;
91+
Statistics& statistics;
9192

9293
private:
9394
struct CacheKey {

source/Options.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ Options::Options(
140140
dump_class_intervals_(false),
141141
dump_overrides_(false),
142142
dump_call_graph_(false),
143+
dump_unresolved_methods_(false),
143144
dump_dependencies_(false),
144145
dump_methods_(false),
145146
dump_coverage_info_(false),
@@ -277,6 +278,7 @@ Options::Options(const boost::program_options::variables_map& variables) {
277278
dump_class_intervals_ = variables.count("dump-class-intervals") > 0;
278279
dump_overrides_ = variables.count("dump-overrides") > 0;
279280
dump_call_graph_ = variables.count("dump-call-graph") > 0;
281+
dump_unresolved_methods_ = variables.count("dump-unresolved-methods") > 0;
280282
dump_dependencies_ = variables.count("dump-dependencies") > 0;
281283
dump_methods_ = variables.count("dump-methods") > 0;
282284
dump_coverage_info_ = variables.count("dump-coverage-info") > 0;
@@ -444,6 +446,8 @@ void Options::add_options(
444446
"dump-overrides", "Dump the override graph in `overrides.json`.");
445447
options.add_options()(
446448
"dump-call-graph", "Dump the call graph in `call_graph.json`.");
449+
options.add_options()(
450+
"dump-unresolved-methods", "Dump the list of unresolved methods in `unresolved_methods.json`.");
447451
options.add_options()(
448452
"dump-dependencies", "Dump the dependency graph in `dependencies.json`.");
449453
options.add_options()(
@@ -579,6 +583,10 @@ const std::filesystem::path Options::call_graph_output_path() const {
579583
return output_directory_;
580584
}
581585

586+
const std::filesystem::path Options::unresolved_methods_output_path() const {
587+
return output_directory_ / "unresolved_methods.json";
588+
}
589+
582590
const std::filesystem::path Options::class_hierarchies_output_path() const {
583591
return output_directory_ / "class_hierarchies.json";
584592
}
@@ -688,6 +696,10 @@ bool Options::dump_call_graph() const {
688696
return dump_call_graph_;
689697
}
690698

699+
bool Options::dump_unresolved_methods() const {
700+
return dump_unresolved_methods_;
701+
}
702+
691703
bool Options::dump_dependencies() const {
692704
return dump_dependencies_;
693705
}

source/Options.h

+3
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ class Options final {
8585
const std::filesystem::path models_output_path() const;
8686
const std::filesystem::path methods_output_path() const;
8787
const std::filesystem::path call_graph_output_path() const;
88+
const std::filesystem::path unresolved_methods_output_path() const;
8889
const std::filesystem::path class_hierarchies_output_path() const;
8990
const std::filesystem::path class_intervals_output_path() const;
9091
const std::filesystem::path overrides_output_path() const;
@@ -115,6 +116,7 @@ class Options final {
115116
bool dump_class_intervals() const;
116117
bool dump_overrides() const;
117118
bool dump_call_graph() const;
119+
bool dump_unresolved_methods() const;
118120
bool dump_dependencies() const;
119121
bool dump_methods() const;
120122
bool dump_coverage_info() const;
@@ -176,6 +178,7 @@ class Options final {
176178
bool dump_class_intervals_;
177179
bool dump_overrides_;
178180
bool dump_call_graph_;
181+
bool dump_unresolved_methods_;
179182
bool dump_dependencies_;
180183
bool dump_methods_;
181184
bool dump_coverage_info_;

source/Registry.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -475,4 +475,12 @@ void Registry::dump_rule_coverage_info(
475475
JsonWriter::write_json_file(output_path, rule_coverage.to_json());
476476
}
477477

478+
void Registry::dump_unresolved_methods(const std::filesystem::path& output_path) const {
479+
auto unresolved_methods_value = Json::Value(Json::arrayValue);
480+
for (const auto& unresolved_method_name : context_.statistics->unresolved_methods()) {
481+
unresolved_methods_value.append(Json::Value(show(unresolved_method_name)));
482+
}
483+
JsonWriter::write_json_file(output_path, unresolved_methods_value);
484+
}
485+
478486
} // namespace marianatrench

source/Registry.h

+1
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ class Registry final {
104104

105105
void dump_file_coverage_info(const std::filesystem::path& path) const;
106106
void dump_rule_coverage_info(const std::filesystem::path& path) const;
107+
void dump_unresolved_methods(const std::filesystem::path& path) const;
107108

108109
std::string dump_models() const;
109110
Json::Value models_to_json() const;

source/Statistics.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,15 @@ void Statistics::log_time(const Method* method, const Timer& timer) {
6262
record);
6363
}
6464

65+
void Statistics::log_unable_to_resolve_call(const DexMethodRef* method) {
66+
std::lock_guard<std::mutex> lock(mutex_);
67+
unresolved_methods_.insert(method);
68+
}
69+
70+
const std::unordered_set<const DexMethodRef*>& Statistics::unresolved_methods() const {
71+
return unresolved_methods_;
72+
}
73+
6574
namespace {
6675

6776
double round(double x, int digits) {
@@ -77,6 +86,8 @@ Json::Value Statistics::to_json() const {
7786
Json::Value(static_cast<Json::UInt64>(number_iterations_));
7887
value["rss"] = Json::Value(round(max_resident_set_size_, 6));
7988
value["cores"] = Json::Value(sparta::parallel::default_num_threads());
89+
value["unresolved_methods"] =
90+
Json::Value(static_cast<Json::UInt64>(unresolved_methods_.size()));
8091

8192
auto times_value = Json::Value(Json::objectValue);
8293
for (const auto& record : times_) {

source/Statistics.h

+7
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,15 @@ class Statistics final {
3232
void log_resident_set_size(double resident_set_size);
3333
void log_time(const std::string& name, const Timer& timer);
3434
void log_time(const Method* method, const Timer& timer);
35+
void log_unable_to_resolve_call(const DexMethodRef* method);
3536

3637
Json::Value to_json() const;
3738

3839
/* Maximum number of slowest methods to record. */
3940
constexpr static std::size_t kRecordSlowestMethods = 20;
4041

42+
const std::unordered_set<const DexMethodRef*>& unresolved_methods() const;
43+
4144
private:
4245
std::mutex mutex_;
4346

@@ -52,6 +55,10 @@ class Statistics final {
5255

5356
//  Sorted list of slowest methods to analyze (from slowest to fastest).
5457
std::vector<std::pair<const Method*, double>> slowest_methods_;
58+
59+
// Set of methods that could not be resolved.
60+
std::unordered_set<const DexMethodRef*> unresolved_methods_ =
61+
std::unordered_set<const DexMethodRef*>();
5562
};
5663

5764
} // namespace marianatrench

source/TransferCall.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <mariana-trench/Log.h>
1313
#include <mariana-trench/Positions.h>
1414
#include <mariana-trench/TransferCall.h>
15+
#include <mariana-trench/Statistics.h>
1516

1617
namespace marianatrench {
1718

@@ -149,11 +150,13 @@ CalleeModel get_callee(
149150
const DexPosition* MT_NULLABLE dex_position,
150151
const std::vector<const DexType * MT_NULLABLE>& source_register_types,
151152
const std::vector<std::optional<std::string>>& source_constant_arguments,
152-
bool is_this_call) {
153+
bool is_this_call,
154+
Statistics& statistics) {
153155
mt_assert(opcode::is_an_invoke(instruction->opcode()));
154156

155157
auto call_target = context->call_graph.callee(context->method(), instruction);
156158
if (!call_target.resolved()) {
159+
statistics.log_unable_to_resolve_call(instruction->get_method());
157160
WARNING_OR_DUMP(
158161
context,
159162
3,

source/TransferCall.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ CalleeModel get_callee(
5555
const DexPosition* MT_NULLABLE position,
5656
const std::vector<const DexType * MT_NULLABLE>& source_register_types,
5757
const std::vector<std::optional<std::string>>& source_constant_arguments,
58-
bool is_this_call);
58+
bool is_this_call,
59+
Statistics& statistics);
5960

6061
CalleeModel get_callee(
6162
const MethodContext* context,

0 commit comments

Comments
 (0)