Fix parsing of shared libraries in class loader context.
The code did not take into account shared libraries depending
on other shared libraries.
bug: 111174995
Test: class_loader_context_test
Change-Id: I0b90cfaff72b5bd7985dbe90b5e72d5988141490
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 0bae60a..9fe39b1 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -107,6 +107,39 @@
}
}
+static size_t FindMatchingSharedLibraryCloseMarker(const std::string& spec,
+ size_t shared_library_open_index) {
+ // Counter of opened shared library marker we've encountered so far.
+ uint32_t counter = 1;
+ // The index at which we're operating in the loop.
+ uint32_t string_index = shared_library_open_index + 1;
+ size_t shared_library_close = std::string::npos;
+ while (counter != 0) {
+ shared_library_close =
+ spec.find_first_of(kClassLoaderSharedLibraryClosingMark, string_index);
+ size_t shared_library_open =
+ spec.find_first_of(kClassLoaderSharedLibraryOpeningMark, string_index);
+ if (shared_library_close == std::string::npos) {
+ // No matching closing marker. Return an error.
+ break;
+ }
+
+ if ((shared_library_open == std::string::npos) ||
+ (shared_library_close < shared_library_open)) {
+ // We have seen a closing marker. Decrement the counter.
+ --counter;
+ // Move the search index forward.
+ string_index = shared_library_close + 1;
+ } else {
+ // New nested opening marker. Increment the counter and move the search
+ // index after the marker.
+ ++counter;
+ string_index = shared_library_open + 1;
+ }
+ }
+ return shared_library_close;
+}
+
// The expected format is:
// "ClassLoaderType1[ClasspathElem1*Checksum1:ClasspathElem2*Checksum2...]{ClassLoaderType2[...]}".
// The checksum part of the format is expected only if parse_cheksums is true.
@@ -160,7 +193,9 @@
}
}
- if (class_loader_spec[class_loader_spec.length() - 1] == kClassLoaderSharedLibraryClosingMark) {
+ if ((class_loader_spec[class_loader_spec.length() - 1] == kClassLoaderSharedLibraryClosingMark) &&
+ (class_loader_spec[class_loader_spec.length() - 2] != kClassLoaderSharedLibraryOpeningMark)) {
+ // Non-empty list of shared libraries.
size_t start_index = class_loader_spec.find_first_of(kClassLoaderSharedLibraryOpeningMark);
if (start_index == std::string::npos) {
return nullptr;
@@ -168,8 +203,43 @@
std::string shared_libraries_spec =
class_loader_spec.substr(start_index + 1, class_loader_spec.length() - start_index - 2);
std::vector<std::string> shared_libraries;
- Split(shared_libraries_spec, kClassLoaderSharedLibrarySeparator, &shared_libraries);
- for (const std::string& shared_library_spec : shared_libraries) {
+ size_t cursor = 0;
+ while (cursor != shared_libraries_spec.length()) {
+ size_t shared_library_separator =
+ shared_libraries_spec.find_first_of(kClassLoaderSharedLibrarySeparator, cursor);
+ size_t shared_library_open =
+ shared_libraries_spec.find_first_of(kClassLoaderSharedLibraryOpeningMark, cursor);
+ std::string shared_library_spec;
+ if (shared_library_separator == std::string::npos) {
+ // Only one shared library, for example:
+ // PCL[...]
+ shared_library_spec =
+ shared_libraries_spec.substr(cursor, shared_libraries_spec.length() - cursor);
+ cursor = shared_libraries_spec.length();
+ } else if ((shared_library_open == std::string::npos) ||
+ (shared_library_open > shared_library_separator)) {
+ // We found a shared library without nested shared libraries, for example:
+ // PCL[...]#PCL[...]{...}
+ shared_library_spec =
+ shared_libraries_spec.substr(cursor, shared_library_separator - cursor);
+ cursor = shared_library_separator + 1;
+ } else {
+ // The shared library contains nested shared libraries. Find the matching closing shared
+ // marker for it.
+ size_t closing_marker =
+ FindMatchingSharedLibraryCloseMarker(shared_libraries_spec, shared_library_open);
+ if (closing_marker == std::string::npos) {
+ // No matching closing marker, return an error.
+ return nullptr;
+ }
+ shared_library_spec = shared_libraries_spec.substr(cursor, closing_marker + 1 - cursor);
+ cursor = closing_marker + 1;
+ if (cursor != shared_libraries_spec.length() &&
+ shared_libraries_spec[cursor] == kClassLoaderSharedLibrarySeparator) {
+ // Pass the shared library separator marker.
+ ++cursor;
+ }
+ }
std::unique_ptr<ClassLoaderInfo> shared_library(
ParseInternal(shared_library_spec, parse_checksums));
if (shared_library == nullptr) {
@@ -250,50 +320,24 @@
// The class loader spec contains shared libraries. Find the matching closing
// shared library marker for it.
- // Counter of opened shared library marker we've encountered so far.
- uint32_t counter = 1;
- // The index at which we're operating in the loop.
- uint32_t string_index = first_shared_library_open + 1;
- while (counter != 0) {
- size_t shared_library_close =
- remaining.find_first_of(kClassLoaderSharedLibraryClosingMark, string_index);
- size_t shared_library_open =
- remaining.find_first_of(kClassLoaderSharedLibraryOpeningMark, string_index);
- if (shared_library_close == std::string::npos) {
- // No matching closing market. Return an error.
- LOG(ERROR) << "Invalid class loader spec: " << class_loader_spec;
- return nullptr;
- }
+ uint32_t shared_library_close =
+ FindMatchingSharedLibraryCloseMarker(remaining, first_shared_library_open);
+ if (shared_library_close == std::string::npos) {
+ LOG(ERROR) << "Invalid class loader spec: " << class_loader_spec;
+ return nullptr;
+ }
+ class_loader_spec = remaining.substr(0, shared_library_close + 1);
- if ((shared_library_open == std::string::npos) ||
- (shared_library_close < shared_library_open)) {
- // We have seen a closing marker. Decrement the counter.
- --counter;
- if (counter == 0) {
- // Found the matching closing marker.
- class_loader_spec = remaining.substr(0, shared_library_close + 1);
-
- // Compute the remaining string to analyze.
- if (remaining.size() == shared_library_close + 1) {
- remaining = "";
- } else if ((remaining.size() == shared_library_close + 2) ||
- (remaining.at(shared_library_close + 1) != kClassLoaderSeparator)) {
- LOG(ERROR) << "Invalid class loader spec: " << class_loader_spec;
- return nullptr;
- } else {
- remaining = remaining.substr(shared_library_close + 2,
- remaining.size() - shared_library_close - 2);
- }
- } else {
- // Move the search index forward.
- string_index = shared_library_close + 1;
- }
- } else {
- // New nested opening marker. Increment the counter and move the search
- // index after the marker.
- ++counter;
- string_index = shared_library_open + 1;
- }
+ // Compute the remaining string to analyze.
+ if (remaining.size() == shared_library_close + 1) {
+ remaining = "";
+ } else if ((remaining.size() == shared_library_close + 2) ||
+ (remaining.at(shared_library_close + 1) != kClassLoaderSeparator)) {
+ LOG(ERROR) << "Invalid class loader spec: " << class_loader_spec;
+ return nullptr;
+ } else {
+ remaining = remaining.substr(shared_library_close + 2,
+ remaining.size() - shared_library_close - 2);
}
}
diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc
index f3e2ac0..0fa4619 100644
--- a/runtime/class_loader_context_test.cc
+++ b/runtime/class_loader_context_test.cc
@@ -284,6 +284,25 @@
VerifyClassLoaderSharedLibraryPCL(context.get(), 0, 0, "s1.dex");
}
+TEST_F(ClassLoaderContextTest, ParseComplexSharedLibraries1) {
+ std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(
+ "PCL[]{PCL[s4.dex]{PCL[s5.dex]{PCL[s6.dex]}#PCL[s6.dex]}}");
+ VerifyContextSize(context.get(), 1);
+ VerifyClassLoaderSharedLibraryPCL(context.get(), 0, 0, "s4.dex");
+}
+
+TEST_F(ClassLoaderContextTest, ParseComplexSharedLibraries2) {
+ std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(
+ "PCL[]{PCL[s1.dex]{PCL[s2.dex]}#PCL[s2.dex]#"
+ "PCL[s3.dex]#PCL[s4.dex]{PCL[s5.dex]{PCL[s6.dex]}#PCL[s6.dex]}#PCL[s5.dex]{PCL[s6.dex]}}");
+ VerifyContextSize(context.get(), 1);
+ VerifyClassLoaderSharedLibraryPCL(context.get(), 0, 0, "s1.dex");
+ VerifyClassLoaderSharedLibraryPCL(context.get(), 0, 1, "s2.dex");
+ VerifyClassLoaderSharedLibraryPCL(context.get(), 0, 2, "s3.dex");
+ VerifyClassLoaderSharedLibraryPCL(context.get(), 0, 3, "s4.dex");
+ VerifyClassLoaderSharedLibraryPCL(context.get(), 0, 4, "s5.dex");
+}
+
TEST_F(ClassLoaderContextTest, ParseValidEmptyContextDLC) {
std::unique_ptr<ClassLoaderContext> context =
ClassLoaderContext::Create("DLC[]");
@@ -316,6 +335,10 @@
ASSERT_TRUE(nullptr == ClassLoaderContext::Create("DLC[s4.dex]}"));
ASSERT_TRUE(nullptr == ClassLoaderContext::Create("DLC[s4.dex]{"));
ASSERT_TRUE(nullptr == ClassLoaderContext::Create("DLC{DLC[s4.dex]}"));
+ ASSERT_TRUE(nullptr == ClassLoaderContext::Create("PCL{##}"));
+ ASSERT_TRUE(nullptr == ClassLoaderContext::Create("PCL{PCL[s4.dex]#}"));
+ ASSERT_TRUE(nullptr == ClassLoaderContext::Create("PCL{PCL[s4.dex]##}"));
+ ASSERT_TRUE(nullptr == ClassLoaderContext::Create("PCL{PCL[s4.dex]{PCL[s3.dex]}#}"));
}
TEST_F(ClassLoaderContextTest, OpenInvalidDexFiles) {