Skip to content

Commit

Permalink
Mark superclasses
Browse files Browse the repository at this point in the history
Summary: Visit and mark superclasses. Also adjust regex matcher to allow * to match nothing at the end of a class name. These changes get us within 12 seeds for full fidelity for FB4A.

Reviewed By: dariorussi

Differential Revision: D4151154

fbshipit-source-id: e24c528c0bef73e78de69612909a71b18a18d078
  • Loading branch information
Satnam Singh authored and Facebook Github Bot committed Nov 9, 2016
1 parent fd805c8 commit dfd1c30
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 27 deletions.
78 changes: 56 additions & 22 deletions libredex/ProguardMatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -344,20 +344,23 @@ bool field_level_match(
return boost::regex_match(dequalified_name, *fieldname_regex);
}

void keep_fields(std::unordered_map<std::string, boost::regex*>& regex_map,
unsigned int keep_fields(std::unordered_map<std::string, boost::regex*>& regex_map,
redex::KeepSpec* keep_rule,
const std::list<DexField*>& fields,
redex::MemberSpecification* fieldSpecification,
const boost::regex* fieldname_regex,
std::function<void(DexField*)> keeper) {
unsigned int count = 0;
for (auto field : fields) {
if (field_level_match(
regex_map, fieldSpecification, field, fieldname_regex)) {
++count;
keeper(field);
fieldSpecification->count++;
apply_keep_modifiers(keep_rule, field);
}
}
return count;
}

std::string field_regex(const MemberSpecification& field_spec) {
Expand All @@ -368,19 +371,21 @@ std::string field_regex(const MemberSpecification& field_spec) {
return ss.str();
}

void apply_field_keeps(
unsigned int apply_field_keeps(
std::unordered_map<std::string, boost::regex*>& regex_map,
const DexClass* cls,
redex::KeepSpec* keep_rule,
std::function<void(DexField*)> keeper) {
unsigned int count = 0;
for (auto& field_spec : keep_rule->class_spec.fieldSpecifications) {
auto fieldname_regex = field_regex(field_spec);
boost::regex* matcher = register_matcher(regex_map, fieldname_regex);
keep_fields(
count += keep_fields(
regex_map, keep_rule, cls->get_ifields(), &field_spec, matcher, keeper);
keep_fields(
count += keep_fields(
regex_map, keep_rule, cls->get_sfields(), &field_spec, matcher, keeper);
}
return count;
}

bool method_level_match(
Expand Down Expand Up @@ -417,20 +422,23 @@ void keep_clinits(DexClass* cls) {
}
}

void keep_methods(std::unordered_map<std::string, boost::regex*>& regex_map,
unsigned int keep_methods(std::unordered_map<std::string, boost::regex*>& regex_map,
KeepSpec* keep_rule,
redex::MemberSpecification* methodSpecification,
const std::list<DexMethod*>& methods,
const boost::regex* method_regex,
std::function<void(DexMethod*)> keeper) {
unsigned int count = 0;
for (const auto& method : methods) {
if (method_level_match(
regex_map, methodSpecification, method, method_regex)) {
++count;
keeper(method);
methodSpecification->count++;
apply_keep_modifiers(keep_rule, method);
}
}
return count;
}

std::string method_regex(const MemberSpecification& method_spec) {
Expand All @@ -442,29 +450,31 @@ std::string method_regex(const MemberSpecification& method_spec) {
return qualified_method_regex;
}

void apply_method_keeps(
unsigned int apply_method_keeps(
std::unordered_map<std::string, boost::regex*>& regex_map,
const DexClass* cls,
redex::KeepSpec* keep_rule,
std::function<void(DexMethod*)> keeper) {
auto methodSpecifications = keep_rule->class_spec.methodSpecifications;
unsigned int count = 0;
for (auto& method_spec : methodSpecifications) {
auto qualified_method_regex = method_regex(method_spec);
boost::regex* method_regex =
register_matcher(regex_map, qualified_method_regex);
keep_methods(regex_map,
count += keep_methods(regex_map,
keep_rule,
&method_spec,
cls->get_vmethods(),
method_regex,
keeper);
keep_methods(regex_map,
count += keep_methods(regex_map,
keep_rule,
&method_spec,
cls->get_dmethods(),
method_regex,
keeper);
}
return count;
}

// This function checks to see of a class satisfies a match
Expand Down Expand Up @@ -540,7 +550,7 @@ bool search_extends_and_interfaces(
regex_map, cls, extends_class_name, annotation)) {
return true;
}
// Do any of the classes and interface above match?
// Do any of the classes and interfaces above match?
auto super_type = cls->get_super_class();
if (super_type && super_type != get_object_type()) {
auto super_class = type_class(super_type);
Expand Down Expand Up @@ -627,20 +637,30 @@ bool class_level_match(
void mark_class_and_members_for_keep(
std::unordered_map<std::string, boost::regex*>& regex_map,
KeepSpec* keep_rule,
DexClass* cls) {
// Apply the keep option modifiers.
apply_keep_modifiers(keep_rule, cls);
cls->rstate.set_keep();
DexClass* cls,
bool conditionally_mark_class = false) {
keep_clinits(cls);
keep_rule->count++;
unsigned int count = 0;
// Apply any field-level keep specifications.
apply_field_keeps(regex_map, cls, keep_rule, [](DexField* f) -> void {
count += apply_field_keeps(regex_map, cls, keep_rule, [](DexField* f) -> void {
f->rstate.set_keep();
});
// Apply any method-level keep specifications.
apply_method_keeps(regex_map, cls, keep_rule, [](DexMethod* m) -> void {
count += apply_method_keeps(regex_map, cls, keep_rule, [](DexMethod* m) -> void {
m->rstate.set_keep();
});
if (!conditionally_mark_class || count > 0) {
// Apply the keep option modifiers.
apply_keep_modifiers(keep_rule, cls);
cls->rstate.set_keep();
}
// Mark superclasses.
if (cls->get_super_class()) {
auto super = type_class(cls->get_super_class());
if (super && !super->is_external())
mark_class_and_members_for_keep(regex_map, keep_rule, super, true);
}
}

DexClass* find_single_class(const ProguardMap& pg_map,
Expand Down Expand Up @@ -728,7 +748,7 @@ bool all_fields_match(std::unordered_map<std::string, boost::regex*>& regex_map,
void process_keepclasseswithmembers(
std::unordered_map<std::string, boost::regex*>& regex_map,
KeepSpec* keep_rule,
DexClass* cls) {
DexClass* cls, bool mark_classes_conditionally) {
if (keep_rule->class_spec.fieldSpecifications.size() == 0 &&
keep_rule->class_spec.methodSpecifications.size() == 0) {
std::cerr << "WARNING: A keepclasseswithmembers rule for class "
Expand All @@ -743,14 +763,21 @@ void process_keepclasseswithmembers(
keep_rule->class_spec.methodSpecifications,
cls->get_vmethods(),
cls->get_dmethods())) {
mark_class_and_members_for_keep(regex_map, keep_rule, cls);
mark_class_and_members_for_keep(regex_map, keep_rule, cls, mark_classes_conditionally);
}
// Mark superclasses
if (cls->get_super_class()) {
auto super = type_class(cls->get_super_class());
if (super && !super->is_external())
process_keepclasseswithmembers(regex_map, keep_rule, super, true);
}
}

void process_keepclassmembers(
std::unordered_map<std::string, boost::regex*>& regex_map,
KeepSpec* keep_rule,
DexClass* cls) {
DexClass* cls,
bool mark_classes_conditionally) {
// Apply the keep option modifiers.
apply_keep_modifiers(keep_rule, cls);
cls->rstate.set_keepclassmembers();
Expand All @@ -764,12 +791,19 @@ void process_keepclassmembers(
apply_method_keeps(regex_map, cls, keep_rule, [](DexMethod* m) -> void {
m->rstate.set_keep();
});
// Mark superclasses
if (cls->get_super_class()) {
auto super = type_class(cls->get_super_class());
if (super && !super->is_external())
process_keepclassmembers(regex_map, keep_rule, super, true);
}
}

void process_assumenosideeffects(
std::unordered_map<std::string, boost::regex*>& regex_map,
KeepSpec* keep_rule,
DexClass* cls) {
DexClass* cls,
bool mark_classes_conditionally) {
// Apply the keep option modifiers.
apply_keep_modifiers(keep_rule, cls);
cls->rstate.set_assumenosideeffects();
Expand All @@ -790,7 +824,7 @@ void process_keep(const ProguardMap& pg_map,
std::function<void(
std::unordered_map<std::string, boost::regex*>& regex_map,
KeepSpec*,
DexClass*)> keep_processor) {
DexClass*, bool)> keep_processor) {
boost::regex* matcher;
for (auto& keep_rule : keep_rules) {
auto descriptor =
Expand All @@ -799,7 +833,7 @@ void process_keep(const ProguardMap& pg_map,
if (cls != nullptr) {
if (class_level_match(regex_map, keep_rule, cls)) {
if (!cls->is_external()) {
keep_processor(regex_map, &keep_rule, cls);
keep_processor(regex_map, &keep_rule, cls, false);
}
}
continue;
Expand All @@ -812,7 +846,7 @@ void process_keep(const ProguardMap& pg_map,
continue;
}
if (class_level_match(regex_map, keep_rule, cls, matcher)) {
keep_processor(regex_map, &keep_rule, cls);
keep_processor(regex_map, &keep_rule, cls, false);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions libredex/ProguardRegex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ std::string form_type_regex(std::string proguard_regex) {
if ((i != proguard_regex.size() - 2) &&
(proguard_regex[i + 2] == '*')) {
// ***: Math any single type i.e. a primitive type or a class type.
r += "\\[*(?:(?:B|S|I|J|Z|F|D|C)|L.*;)";
r += "\\[*(?:(?:B|S|I|J|Z|F|D|C|V)|L.*;)";
i = i + 2;
continue;
}
Expand All @@ -104,7 +104,7 @@ std::string form_type_regex(std::string proguard_regex) {
i++;
continue;
}
r += "([^\\/]+)";
r += "([^\\/]*)";
continue;
}
if (ch == '.') {
Expand Down
6 changes: 3 additions & 3 deletions test/unit/ProguardRegexTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ TEST(ProguardRegexTest, types) {
auto descriptor = proguard_parser::convert_wildcard_type(proguard_regex);
boost::cmatch m;
auto r = proguard_parser::form_type_regex(descriptor);
ASSERT_EQ("Lcom\\/([^\\/]+)\\/redex\\/test\\/proguard\\/Delta;", r);
ASSERT_EQ("Lcom\\/([^\\/]*)\\/redex\\/test\\/proguard\\/Delta;", r);
boost::regex matcher(r);
ASSERT_TRUE(boost::regex_match("Lcom/facebook/redex/test/proguard/Delta;", m, matcher));
ASSERT_EQ(2, m.size());
Expand All @@ -116,7 +116,7 @@ TEST(ProguardRegexTest, types) {
auto descriptor = proguard_parser::convert_wildcard_type(proguard_regex);
boost::cmatch m;
auto r = proguard_parser::form_type_regex(descriptor);
ASSERT_EQ("Lcom\\/([^\\/]+)\\/redex\\/([^\\/]+)\\/proguard\\/Delta;", r);
ASSERT_EQ("Lcom\\/([^\\/]*)\\/redex\\/([^\\/]*)\\/proguard\\/Delta;", r);
boost::regex matcher(r);
ASSERT_TRUE(boost::regex_match("Lcom/facebook/redex/test/proguard/Delta;", m, matcher));
ASSERT_EQ(3, m.size());
Expand Down Expand Up @@ -205,7 +205,7 @@ TEST(ProguardRegexTest, types) {
auto proguard_regex = "***";
auto descriptor = proguard_parser::convert_wildcard_type(proguard_regex);
auto r = proguard_parser::form_type_regex(descriptor);
ASSERT_EQ("\\[*(?:(?:B|S|I|J|Z|F|D|C)|L.*;)", r);
ASSERT_EQ("\\[*(?:(?:B|S|I|J|Z|F|D|C|V)|L.*;)", r);
boost::regex matcher(r);
ASSERT_TRUE(boost::regex_match("Ljava/lang/String;", matcher));
ASSERT_TRUE(boost::regex_match("I", matcher));
Expand Down

0 comments on commit dfd1c30

Please sign in to comment.