Skip to content

Commit

Permalink
Add hook for allowed duplicates to JarLoader
Browse files Browse the repository at this point in the history
Summary: As title. In follow-up diffs this will be used to reduce the amount of allowed duplicates, but give a configuration point.

Reviewed By: wsanville

Differential Revision: D48124363

fbshipit-source-id: 3ab6c50506943d2e481e38edb4ce96558649a050
  • Loading branch information
agampe authored and facebook-github-bot committed Aug 30, 2023
1 parent 53603c3 commit cfaacba
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 23 deletions.
51 changes: 32 additions & 19 deletions libredex/JarLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@ bool parse_class(uint8_t* buffer,
size_t buffer_size,
Scope* classes,
attribute_hook_t attr_hook,
const jar_loader::duplicate_allowed_hook_t& is_allowed,
const DexLocation* jar_location) {
auto buffer_end = buffer + buffer_size;
uint32_t magic = read32(buffer, buffer_end);
Expand Down Expand Up @@ -445,11 +446,7 @@ bool parse_class(uint8_t* buffer,
SHOW(self), jar_location->get_file_name().c_str(),
cls->get_location()->get_file_name().c_str());

// TODO: There are still blocking issues in instrumentation test that are
// blocking. We currently only fail for duplicate `android*` classes,
// we can make this throw for all the classes once they are fixed.

if (boost::starts_with(cls->str(), "Landroid")) {
if (!is_allowed(cls, jar_location->get_file_name())) {
throw RedexException(RedexError::DUPLICATE_CLASSES,
"Found duplicate class in two different files.",
{{"class", SHOW(self)},
Expand Down Expand Up @@ -577,8 +574,10 @@ bool load_class_file(const std::string& filename, Scope* classes) {
auto buffer = std::make_unique<char[]>(size);
buf->sgetn(buffer.get(), size);
auto jar_location = DexLocation::make_location("", filename);
return parse_class(reinterpret_cast<uint8_t*>(buffer.get()), size, classes,
/* attr_hook */ nullptr, jar_location);
return parse_class(
reinterpret_cast<uint8_t*>(buffer.get()), size, classes,
/* attr_hook */ nullptr,
/* is_allowed=*/[](auto*, auto&) { return true; }, jar_location);
}

/******************
Expand Down Expand Up @@ -845,12 +844,14 @@ bool decompress_class(jar_entry& file,

constexpr size_t kStartBufferSize = 128 * 1024;

bool process_jar_entries(const DexLocation* location,
std::vector<jar_entry>& files,
const uint8_t* mapping,
const size_t map_size,
Scope* classes,
const attribute_hook_t& attr_hook) {
bool process_jar_entries(
const DexLocation* location,
std::vector<jar_entry>& files,
const uint8_t* mapping,
const size_t map_size,
Scope* classes,
const attribute_hook_t& attr_hook,
const jar_loader::duplicate_allowed_hook_t& is_allowed) {
ssize_t bufsize = kStartBufferSize;
std::unique_ptr<uint8_t[]> outbuffer = std::make_unique<uint8_t[]>(bufsize);
constexpr std::string_view kClassEndString = ".class";
Expand All @@ -876,7 +877,8 @@ bool process_jar_entries(const DexLocation* location,
return false;
}

if (!parse_class(outbuffer.get(), bufsize, classes, attr_hook, location)) {
if (!parse_class(outbuffer.get(), bufsize, classes, attr_hook, is_allowed,
location)) {
return false;
}
}
Expand All @@ -885,11 +887,20 @@ bool process_jar_entries(const DexLocation* location,

} // namespace

namespace jar_loader {

bool default_duplicate_allow_fn(const DexClass* c, const std::string&) {
return !boost::starts_with(c->str(), "Landroid");
}

} // namespace jar_loader

bool process_jar(const DexLocation* location,
const uint8_t* mapping,
size_t size,
Scope* classes,
const attribute_hook_t& attr_hook) {
const attribute_hook_t& attr_hook,
const jar_loader::duplicate_allowed_hook_t& is_allowed) {
pk_cdir_end pce;
std::vector<jar_entry> files;
if (!find_central_directory(mapping, size, pce)) {
Expand All @@ -901,16 +912,17 @@ bool process_jar(const DexLocation* location,
if (!get_jar_entries(mapping, size, pce, files)) {
return false;
}
if (!process_jar_entries(location, files, mapping, size, classes,
attr_hook)) {
if (!process_jar_entries(location, files, mapping, size, classes, attr_hook,
is_allowed)) {
return false;
}
return true;
}

bool load_jar_file(const DexLocation* location,
Scope* classes,
const attribute_hook_t& attr_hook) {
const attribute_hook_t& attr_hook,
const jar_loader::duplicate_allowed_hook_t& is_allowed) {
boost::iostreams::mapped_file file;
try {
file.open(location->get_file_name().c_str(),
Expand All @@ -922,7 +934,8 @@ bool load_jar_file(const DexLocation* location,
}

auto mapping = reinterpret_cast<const uint8_t*>(file.const_data());
if (!process_jar(location, mapping, file.size(), classes, attr_hook)) {
if (!process_jar(location, mapping, file.size(), classes, attr_hook,
is_allowed)) {
std::cerr << "error: cannot process jar: " << location->get_file_name()
<< "\n";
return false;
Expand Down
19 changes: 17 additions & 2 deletions libredex/JarLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#pragma once

class DexClass;
class DexLocation;
class DexField;
class DexMethod;
Expand All @@ -29,9 +30,21 @@ using attribute_hook_t =
uint8_t* attribute_pointer,
uint8_t* attribute_pointer_end)>;

namespace jar_loader {

using duplicate_allowed_hook_t =
std::function<bool(const DexClass*, const std::string&)>;

// Legacy implementation for other clients.
bool default_duplicate_allow_fn(const DexClass* c, const std::string& jar_name);

} // namespace jar_loader

bool load_jar_file(const DexLocation* location,
Scope* classes = nullptr,
const attribute_hook_t& = nullptr);
const attribute_hook_t& attr_hook = nullptr,
const jar_loader::duplicate_allowed_hook_t& is_allowed =
jar_loader::default_duplicate_allow_fn);

bool load_class_file(const std::string& filename, Scope* classes = nullptr);

Expand All @@ -40,10 +53,12 @@ bool process_jar(const DexLocation* location,
const uint8_t* mapping,
size_t size,
Scope* classes,
const attribute_hook_t& attr_hook);
const attribute_hook_t& attr_hook,
const jar_loader::duplicate_allowed_hook_t& is_allowed);

bool parse_class(uint8_t* buffer,
size_t buffer_size,
Scope* classes,
attribute_hook_t attr_hook,
const jar_loader::duplicate_allowed_hook_t& is_allowed,
const DexLocation* jar_location);
7 changes: 5 additions & 2 deletions tools/redex-all/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1199,10 +1199,13 @@ void redex_frontend(ConfigFiles& conf, /* input */
for (const auto& library_jar : library_jars) {
TRACE(MAIN, 1, "LIBRARY JAR: %s", library_jar.c_str());
if (!load_jar_file(DexLocation::make_location("", library_jar),
&external_classes)) {
&external_classes, /*attr_hook=*/nullptr,
jar_loader::default_duplicate_allow_fn)) {
// Try again with the basedir
std::string basedir_path = pg_config.basedirectory + "/" + library_jar;
if (!load_jar_file(DexLocation::make_location("", basedir_path))) {
if (!load_jar_file(DexLocation::make_location("", basedir_path),
/*classes=*/nullptr, /*attr_hook=*/nullptr,
jar_loader::default_duplicate_allow_fn)) {
std::cerr << "error: library jar could not be loaded: " << library_jar
<< std::endl;
exit(EXIT_FAILURE);
Expand Down

0 comments on commit cfaacba

Please sign in to comment.