diff options
| author | 2020-04-06 19:29:45 -0700 | |
|---|---|---|
| committer | 2020-04-08 23:49:43 +0000 | |
| commit | b495e7ffac8782dd2fc7c1a7fa7c69da71d98c1c (patch) | |
| tree | 723728edcc663257640a6d0b82785992174c6f1b /runtime/class_loader_context.cc | |
| parent | 82cc2a247d9fb9bb8d1d28a09d978f66d0b1c4dd (diff) | |
Log an error when an app loads duplicate dex files
Creating a class loader with duplicate dex files in its classpath is most
likely an unintended bug. That leads to rejecting any compiled code and
hurts performance by extracting in memory.
Test: run-test gtest
Bug: 149410951
Change-Id: Ieebb69c6bd03acbe95dd8bedb6101d70390b92d8
Diffstat (limited to 'runtime/class_loader_context.cc')
| -rw-r--r-- | runtime/class_loader_context.cc | 99 |
1 files changed, 68 insertions, 31 deletions
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc index 98db62ef38..d2119db3ee 100644 --- a/runtime/class_loader_context.cc +++ b/runtime/class_loader_context.cc @@ -1277,6 +1277,43 @@ static inline bool AbsolutePathHasRelativeSuffix(const std::string& path, (std::string_view(path).substr(/*pos*/ path.size() - suffix.size()) == suffix); } +// Returns true if the given dex names are mathing, false otherwise. +static bool AreDexNameMatching(const std::string& actual_dex_name, + const std::string& expected_dex_name) { + // Compute the dex location that must be compared. + // We shouldn't do a naive comparison `actual_dex_name == expected_dex_name` + // because even if they refer to the same file, one could be encoded as a relative location + // and the other as an absolute one. + bool is_dex_name_absolute = IsAbsoluteLocation(actual_dex_name); + bool is_expected_dex_name_absolute = IsAbsoluteLocation(expected_dex_name); + bool dex_names_match = false; + + if (is_dex_name_absolute == is_expected_dex_name_absolute) { + // If both locations are absolute or relative then compare them as they are. + // This is usually the case for: shared libraries and secondary dex files. + dex_names_match = (actual_dex_name == expected_dex_name); + } else if (is_dex_name_absolute) { + // The runtime name is absolute but the compiled name (the expected one) is relative. + // This is the case for split apks which depend on base or on other splits. + dex_names_match = + AbsolutePathHasRelativeSuffix(actual_dex_name, expected_dex_name); + } else if (is_expected_dex_name_absolute) { + // The runtime name is relative but the compiled name is absolute. + // There is no expected use case that would end up here as dex files are always loaded + // with their absolute location. However, be tolerant and do the best effort (in case + // there are unexpected new use case...). + dex_names_match = + AbsolutePathHasRelativeSuffix(expected_dex_name, actual_dex_name); + } else { + // Both locations are relative. In this case there's not much we can be sure about + // except that the names are the same. The checksum will ensure that the files are + // are same. This should not happen outside testing and manual invocations. + dex_names_match = (actual_dex_name == expected_dex_name); + } + + return dex_names_match; +} + bool ClassLoaderContext::ClassLoaderInfoMatch( const ClassLoaderInfo& info, const ClassLoaderInfo& expected_info, @@ -1305,37 +1342,7 @@ bool ClassLoaderContext::ClassLoaderInfoMatch( if (verify_names) { for (size_t k = 0; k < info.classpath.size(); k++) { - // Compute the dex location that must be compared. - // We shouldn't do a naive comparison `info.classpath[k] == expected_info.classpath[k]` - // because even if they refer to the same file, one could be encoded as a relative location - // and the other as an absolute one. - bool is_dex_name_absolute = IsAbsoluteLocation(info.classpath[k]); - bool is_expected_dex_name_absolute = IsAbsoluteLocation(expected_info.classpath[k]); - bool dex_names_match = false; - - - if (is_dex_name_absolute == is_expected_dex_name_absolute) { - // If both locations are absolute or relative then compare them as they are. - // This is usually the case for: shared libraries and secondary dex files. - dex_names_match = (info.classpath[k] == expected_info.classpath[k]); - } else if (is_dex_name_absolute) { - // The runtime name is absolute but the compiled name (the expected one) is relative. - // This is the case for split apks which depend on base or on other splits. - dex_names_match = - AbsolutePathHasRelativeSuffix(info.classpath[k], expected_info.classpath[k]); - } else if (is_expected_dex_name_absolute) { - // The runtime name is relative but the compiled name is absolute. - // There is no expected use case that would end up here as dex files are always loaded - // with their absolute location. However, be tolerant and do the best effort (in case - // there are unexpected new use case...). - dex_names_match = - AbsolutePathHasRelativeSuffix(expected_info.classpath[k], info.classpath[k]); - } else { - // Both locations are relative. In this case there's not much we can be sure about - // except that the names are the same. The checksum will ensure that the files are - // are same. This should not happen outside testing and manual invocations. - dex_names_match = (info.classpath[k] == expected_info.classpath[k]); - } + bool dex_names_match = AreDexNameMatching(info.classpath[k], expected_info.classpath[k]); // Compare the locations. if (!dex_names_match) { @@ -1393,4 +1400,34 @@ bool ClassLoaderContext::ClassLoaderInfoMatch( } } +std::vector<const DexFile*> ClassLoaderContext::CheckForDuplicateDexFiles( + const std::vector<const DexFile*>& dex_files_to_check) { + DCHECK(dex_files_open_attempted_); + DCHECK(dex_files_open_result_); + + std::vector<const DexFile*> result; + + if (special_shared_library_) { + return result; + } + + std::vector<ClassLoaderInfo*> work_list; + work_list.push_back(class_loader_chain_.get()); + while (!work_list.empty()) { + ClassLoaderInfo* info = work_list.back(); + work_list.pop_back(); + for (size_t k = 0; k < info->classpath.size(); k++) { + for (const DexFile* dex_file : dex_files_to_check) { + if (info->checksums[k] == dex_file->GetLocationChecksum() + && AreDexNameMatching(info->classpath[k], dex_file->GetLocation())) { + result.push_back(dex_file); + } + } + } + AddToWorkList(info, work_list); + } + + return result; +} + } // namespace art |