ART: Don't prepend '/' if classpath_dir is empty
When no classpath_dir is given, do not prepend '/' to a relative
dex location.
Add tests.
Bug: 65318303
Test: m test-art-host-gtest-class_loader_context_test
Test: m test-art-host
Change-Id: Ib374815ce3fa9d67694f3a23037cd3b8eea35173
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index e97c6a0..07afedf 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -206,7 +206,7 @@
for (const std::string& cp_elem : info.classpath) {
// If path is relative, append it to the provided base directory.
std::string raw_location = cp_elem;
- if (raw_location[0] != '/') {
+ if (raw_location[0] != '/' && !classpath_dir.empty()) {
raw_location = classpath_dir + '/' + raw_location;
}
diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc
index 458f9f3..930160f 100644
--- a/runtime/class_loader_context_test.cc
+++ b/runtime/class_loader_context_test.cc
@@ -14,9 +14,12 @@
* limitations under the License.
*/
+#include "class_loader_context.h"
+
#include <gtest/gtest.h>
#include <stdlib.h>
+#include "android-base/strings.h"
#include "base/dchecked_vector.h"
#include "base/stl_util.h"
@@ -72,10 +75,21 @@
context, index, ClassLoaderContext::kDelegateLastClassLoader, test_name);
}
+ enum class LocationCheck {
+ kEquals,
+ kEndsWith
+ };
+ enum class BaseLocationCheck {
+ kEquals,
+ kEndsWith
+ };
+
void VerifyOpenDexFiles(
ClassLoaderContext* context,
size_t index,
- std::vector<std::vector<std::unique_ptr<const DexFile>>*>& all_dex_files) {
+ std::vector<std::vector<std::unique_ptr<const DexFile>>*>& all_dex_files,
+ LocationCheck mode = LocationCheck::kEquals,
+ BaseLocationCheck base_mode = BaseLocationCheck::kEquals) {
ASSERT_TRUE(context != nullptr);
ASSERT_TRUE(context->dex_files_open_attempted_);
ASSERT_TRUE(context->dex_files_open_result_);
@@ -98,7 +112,16 @@
expected_location.assign(expected_real_location.get());
expected_location += DexFile::GetMultiDexSuffix(expected_dex_file->GetLocation());
- ASSERT_EQ(expected_location, opened_dex_file->GetLocation());
+ switch (mode) {
+ case LocationCheck::kEquals:
+ ASSERT_EQ(expected_dex_file->GetLocation(), opened_dex_file->GetLocation());
+ break;
+ case LocationCheck::kEndsWith:
+ ASSERT_TRUE(android::base::EndsWith(expected_dex_file->GetLocation(),
+ opened_dex_file->GetLocation().c_str()))
+ << opened_dex_file->GetLocation() << " vs " << expected_dex_file->GetLocation();
+ break;
+ }
ASSERT_EQ(expected_dex_file->GetLocationChecksum(), opened_dex_file->GetLocationChecksum());
std::string class_path_location = info.classpath[k];
@@ -106,7 +129,17 @@
realpath(class_path_location.c_str(), nullptr));
ASSERT_TRUE(class_path_location_real != nullptr);
class_path_location.assign(class_path_location_real.get());
- ASSERT_EQ(class_path_location, opened_dex_file->GetBaseLocation());
+ switch (base_mode) {
+ case BaseLocationCheck::kEquals:
+ ASSERT_EQ(class_path_location, opened_dex_file->GetBaseLocation());
+ break;
+
+ case BaseLocationCheck::kEndsWith:
+ ASSERT_TRUE(android::base::EndsWith(opened_dex_file->GetBaseLocation(),
+ class_path_location.c_str()))
+ << info.classpath[k] << " vs " << opened_dex_file->GetBaseLocation();
+ break;
+ }
}
}
}
@@ -304,6 +337,77 @@
VerifyOpenDexFiles(context.get(), 0, all_dex_files0);
}
+static std::string CreateRelativeString(const std::string& in, const char* cwd) {
+ if (!android::base::StartsWith(in, cwd)) {
+ LOG(FATAL) << in << " " << cwd;
+ }
+ return in.substr(strlen(cwd) + 1);
+}
+
+TEST_F(ClassLoaderContextTest, OpenValidDexFilesRelative) {
+ char cwd_buf[4096];
+ if (getcwd(cwd_buf, arraysize(cwd_buf)) == nullptr) {
+ PLOG(FATAL) << "Could not get working directory";
+ }
+ std::string multidex_name = CreateRelativeString(GetTestDexFileName("MultiDex"), cwd_buf);
+ std::vector<std::unique_ptr<const DexFile>> multidex_files = OpenTestDexFiles("MultiDex");
+ std::string myclass_dex_name = CreateRelativeString(GetTestDexFileName("MyClass"), cwd_buf);
+ std::vector<std::unique_ptr<const DexFile>> myclass_dex_files = OpenTestDexFiles("MyClass");
+ std::string dex_name = CreateRelativeString(GetTestDexFileName("Main"), cwd_buf);
+ std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("Main");
+
+
+ std::unique_ptr<ClassLoaderContext> context =
+ ClassLoaderContext::Create(
+ "PCL[" + multidex_name + ":" + myclass_dex_name + "];" +
+ "DLC[" + dex_name + "]");
+
+ ASSERT_TRUE(context->OpenDexFiles(InstructionSet::kArm, /*classpath_dir*/ ""));
+
+ VerifyContextSize(context.get(), 2);
+ std::vector<std::vector<std::unique_ptr<const DexFile>>*> all_dex_files0;
+ all_dex_files0.push_back(&multidex_files);
+ all_dex_files0.push_back(&myclass_dex_files);
+ std::vector<std::vector<std::unique_ptr<const DexFile>>*> all_dex_files1;
+ all_dex_files1.push_back(&dex_files);
+
+ VerifyOpenDexFiles(context.get(), 0, all_dex_files0, LocationCheck::kEndsWith);
+ VerifyOpenDexFiles(context.get(), 1, all_dex_files1, LocationCheck::kEndsWith);
+}
+
+TEST_F(ClassLoaderContextTest, OpenValidDexFilesClasspathDir) {
+ char cwd_buf[4096];
+ if (getcwd(cwd_buf, arraysize(cwd_buf)) == nullptr) {
+ PLOG(FATAL) << "Could not get working directory";
+ }
+ std::string multidex_name = CreateRelativeString(GetTestDexFileName("MultiDex"), cwd_buf);
+ std::vector<std::unique_ptr<const DexFile>> multidex_files = OpenTestDexFiles("MultiDex");
+ std::string myclass_dex_name = CreateRelativeString(GetTestDexFileName("MyClass"), cwd_buf);
+ std::vector<std::unique_ptr<const DexFile>> myclass_dex_files = OpenTestDexFiles("MyClass");
+ std::string dex_name = CreateRelativeString(GetTestDexFileName("Main"), cwd_buf);
+ std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("Main");
+
+
+ std::unique_ptr<ClassLoaderContext> context =
+ ClassLoaderContext::Create(
+ "PCL[" + multidex_name + ":" + myclass_dex_name + "];" +
+ "DLC[" + dex_name + "]");
+
+ ASSERT_TRUE(context->OpenDexFiles(InstructionSet::kArm, cwd_buf));
+
+ VerifyContextSize(context.get(), 2);
+ std::vector<std::vector<std::unique_ptr<const DexFile>>*> all_dex_files0;
+ all_dex_files0.push_back(&multidex_files);
+ all_dex_files0.push_back(&myclass_dex_files);
+ std::vector<std::vector<std::unique_ptr<const DexFile>>*> all_dex_files1;
+ all_dex_files1.push_back(&dex_files);
+
+ VerifyOpenDexFiles(
+ context.get(), 0, all_dex_files0, LocationCheck::kEquals, BaseLocationCheck::kEndsWith);
+ VerifyOpenDexFiles(
+ context.get(), 1, all_dex_files1, LocationCheck::kEquals, BaseLocationCheck::kEndsWith);
+}
+
TEST_F(ClassLoaderContextTest, OpenInvalidDexFilesMix) {
std::string dex_name = GetTestDexFileName("Main");
std::unique_ptr<ClassLoaderContext> context =