summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jiakai Zhang <jiakaiz@google.com> 2022-08-25 14:03:26 +0100
committer Jiakai Zhang <jiakaiz@google.com> 2022-09-05 12:24:25 +0100
commit28451dc19280f0c1991f9af6f3c087f3ec08de79 (patch)
tree2e4123d8648c147618d2b0bc4761277a9e3a073f
parent94383b4038970838ded1f0a482f16d8b612a4701 (diff)
Fix `ClassLinker::AppendToBootClassPath` usages.
Both `Runtime` and `ClassLinker` maintain information about bootclasspath, and they should keep in sync. However, some test and jvmti code dynamically add elements to bootclasspath by only calling `ClassLinker::AppendToBootClassPath`. This can break oat file validation because the validation is based on the bootclasspath that `Runtime` maintains. This CL fixes them by adding elements through `Runtime`, which updates both itself and `ClassLinker`. Bug: 243128839 Test: art/test.py -b -r --host --debug --cdex-fast --optimizing \ --redefine-stress --debuggable Test: art/test.py -b -r --host --debug Test: art/test.py -b -g --host --debug Change-Id: I92a2c039080abf30455f375628ec9351c35e1897
-rw-r--r--dex2oat/linker/image_test.h13
-rw-r--r--openjdkjvmti/ti_class_loader.cc3
-rw-r--r--openjdkjvmti/ti_redefine.cc13
-rw-r--r--runtime/class_linker.h3
-rw-r--r--runtime/runtime.cc59
-rw-r--r--runtime/runtime.h17
6 files changed, 87 insertions, 21 deletions
diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h
index b570d99e64..52e53e672e 100644
--- a/dex2oat/linker/image_test.h
+++ b/dex2oat/linker/image_test.h
@@ -63,6 +63,7 @@ static const uintptr_t kRequestedImageBase = ART_BASE_ADDRESS;
struct CompilationHelper {
std::vector<std::string> dex_file_locations;
std::vector<ScratchFile> image_locations;
+ std::string extra_dex;
std::vector<std::unique_ptr<const DexFile>> extra_dex_files;
std::vector<ScratchFile> image_files;
std::vector<ScratchFile> oat_files;
@@ -150,18 +151,11 @@ inline std::vector<size_t> CompilationHelper::GetImageObjectSectionSizes() {
inline void ImageTest::DoCompile(ImageHeader::StorageMode storage_mode,
/*out*/ CompilationHelper& out_helper) {
CompilerDriver* driver = compiler_driver_.get();
+ Runtime::Current()->AppendToBootClassPath(
+ out_helper.extra_dex, out_helper.extra_dex, out_helper.extra_dex_files);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
std::vector<const DexFile*> class_path = class_linker->GetBootClassPath();
- for (const std::unique_ptr<const DexFile>& dex_file : out_helper.extra_dex_files) {
- {
- ScopedObjectAccess soa(Thread::Current());
- // Inject in boot class path so that the compiler driver can see it.
- class_linker->AppendToBootClassPath(soa.Self(), dex_file.get());
- }
- class_path.push_back(dex_file.get());
- }
-
// Enable write for dex2dex.
for (const DexFile* dex_file : class_path) {
out_helper.dex_file_locations.push_back(dex_file->GetLocation());
@@ -368,6 +362,7 @@ inline void ImageTest::Compile(
compiler_options_->SetMaxImageBlockSize(max_image_block_size);
image_classes_.clear();
if (!extra_dex.empty()) {
+ helper.extra_dex = extra_dex;
helper.extra_dex_files = OpenTestDexFiles(extra_dex.c_str());
}
DoCompile(storage_mode, helper);
diff --git a/openjdkjvmti/ti_class_loader.cc b/openjdkjvmti/ti_class_loader.cc
index d0a66343e7..cf825344a6 100644
--- a/openjdkjvmti/ti_class_loader.cc
+++ b/openjdkjvmti/ti_class_loader.cc
@@ -66,7 +66,8 @@ bool ClassLoaderHelper::AddToClassLoader(art::Thread* self,
art::ScopedObjectAccessUnchecked soa(self);
art::StackHandleScope<3> hs(self);
if (art::ClassLinker::IsBootClassLoader(soa, loader.Get())) {
- art::Runtime::Current()->GetClassLinker()->AppendToBootClassPath(self, dex_file);
+ art::Runtime::Current()->AppendToBootClassPath(
+ dex_file->GetLocation(), dex_file->GetLocation(), {dex_file});
return true;
}
art::Handle<art::mirror::Object> java_dex_file_obj(
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc
index 59f93c5fc9..2521ff38b4 100644
--- a/openjdkjvmti/ti_redefine.cc
+++ b/openjdkjvmti/ti_redefine.cc
@@ -512,8 +512,15 @@ template jvmtiError Redefiner::GetClassRedefinitionError<RedefinitionType::kStru
art::MemMap Redefiner::MoveDataToMemMap(const std::string& original_location,
art::ArrayRef<const unsigned char> data,
std::string* error_msg) {
+ std::string modified_location = StringPrintf("%s-transformed", original_location.c_str());
+ // A dangling multi-dex location appended to bootclasspath can cause inaccuracy in oat file
+ // validation. For simplicity, just convert it to a normal location.
+ size_t pos = modified_location.find(art::DexFileLoader::kMultiDexSeparator);
+ if (pos != std::string::npos) {
+ modified_location[pos] = '-';
+ }
art::MemMap map = art::MemMap::MapAnonymous(
- StringPrintf("%s-transformed", original_location.c_str()).c_str(),
+ modified_location.c_str(),
data.size(),
PROT_READ|PROT_WRITE,
/*low_4gb=*/ false,
@@ -2481,7 +2488,9 @@ jvmtiError Redefiner::Run() {
art::ClassLinker* cl = runtime_->GetClassLinker();
if (data.GetSourceClassLoader() == nullptr) {
// AppendToBootClassPath includes dex file registration.
- cl->AppendToBootClassPath(&data.GetRedefinition().GetDexFile(), data.GetNewDexCache());
+ const art::DexFile& dex_file = data.GetRedefinition().GetDexFile();
+ runtime_->AppendToBootClassPath(
+ dex_file.GetLocation(), dex_file.GetLocation(), {{&dex_file, data.GetNewDexCache()}});
} else {
cl->RegisterExistingDexCache(data.GetNewDexCache(), data.GetSourceClassLoader());
}
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 1ac47562b2..eb97140921 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -176,6 +176,7 @@ class ClassLinker {
// Add boot class path dex files that were not included in the boot image.
// ClassLinker takes ownership of these dex files.
+ // DO NOT use directly. Use `Runtime::AddExtraBootDexFiles`.
void AddExtraBootDexFiles(Thread* self,
std::vector<std::unique_ptr<const DexFile>>&& additional_dex_files)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -780,10 +781,12 @@ class ClassLinker {
REQUIRES_SHARED(Locks::mutator_lock_)
NO_THREAD_SAFETY_ANALYSIS;
+ // DO NOT use directly. Use `Runtime::AppendToBootClassPath`.
void AppendToBootClassPath(Thread* self, const DexFile* dex_file)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_);
+ // DO NOT use directly. Use `Runtime::AppendToBootClassPath`.
void AppendToBootClassPath(const DexFile* dex_file, ObjPtr<mirror::DexCache> dex_cache)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_);
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 390fcf06d0..6e583afe82 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -16,6 +16,8 @@
#include "runtime.h"
+#include <utility>
+
#ifdef __linux__
#include <sys/prctl.h>
#endif
@@ -3477,28 +3479,69 @@ bool Runtime::HasImageWithProfile() const {
return false;
}
-void Runtime::AppendToBootClassPath(
- const std::string& filename,
- const std::string& location,
- const std::vector<std::unique_ptr<const art::DexFile>>& dex_files) {
+void Runtime::AppendToBootClassPath(const std::string& filename, const std::string& location) {
+ DCHECK(!DexFileLoader::IsMultiDexLocation(filename.c_str()));
boot_class_path_.push_back(filename);
if (!boot_class_path_locations_.empty()) {
+ DCHECK(!DexFileLoader::IsMultiDexLocation(location.c_str()));
boot_class_path_locations_.push_back(location);
}
+}
+
+void Runtime::AppendToBootClassPath(
+ const std::string& filename,
+ const std::string& location,
+ const std::vector<std::unique_ptr<const art::DexFile>>& dex_files) {
+ AppendToBootClassPath(filename, location);
ScopedObjectAccess soa(Thread::Current());
for (const std::unique_ptr<const art::DexFile>& dex_file : dex_files) {
+ // The first element must not be at a multi-dex location, while other elements must be.
+ DCHECK_NE(DexFileLoader::IsMultiDexLocation(dex_file->GetLocation().c_str()),
+ dex_file.get() == dex_files.begin()->get());
GetClassLinker()->AppendToBootClassPath(Thread::Current(), dex_file.get());
}
}
+void Runtime::AppendToBootClassPath(const std::string& filename,
+ const std::string& location,
+ const std::vector<const art::DexFile*>& dex_files) {
+ AppendToBootClassPath(filename, location);
+ ScopedObjectAccess soa(Thread::Current());
+ for (const art::DexFile* dex_file : dex_files) {
+ // The first element must not be at a multi-dex location, while other elements must be.
+ DCHECK_NE(DexFileLoader::IsMultiDexLocation(dex_file->GetLocation().c_str()),
+ dex_file == *dex_files.begin());
+ GetClassLinker()->AppendToBootClassPath(Thread::Current(), dex_file);
+ }
+}
+
+void Runtime::AppendToBootClassPath(
+ const std::string& filename,
+ const std::string& location,
+ const std::vector<std::pair<const art::DexFile*, ObjPtr<mirror::DexCache>>>&
+ dex_files_and_cache) {
+ AppendToBootClassPath(filename, location);
+ ScopedObjectAccess soa(Thread::Current());
+ for (const auto& [dex_file, dex_cache] : dex_files_and_cache) {
+ // The first element must not be at a multi-dex location, while other elements must be.
+ DCHECK_NE(DexFileLoader::IsMultiDexLocation(dex_file->GetLocation().c_str()),
+ dex_file == dex_files_and_cache.begin()->first);
+ GetClassLinker()->AppendToBootClassPath(dex_file, dex_cache);
+ }
+}
+
void Runtime::AddExtraBootDexFiles(const std::string& filename,
const std::string& location,
std::vector<std::unique_ptr<const art::DexFile>>&& dex_files) {
- boot_class_path_.push_back(filename);
- if (!boot_class_path_locations_.empty()) {
- boot_class_path_locations_.push_back(location);
- }
+ AppendToBootClassPath(filename, location);
ScopedObjectAccess soa(Thread::Current());
+ if (kIsDebugBuild) {
+ for (const std::unique_ptr<const art::DexFile>& dex_file : dex_files) {
+ // The first element must not be at a multi-dex location, while other elements must be.
+ DCHECK_NE(DexFileLoader::IsMultiDexLocation(dex_file->GetLocation().c_str()),
+ dex_file.get() == dex_files.begin()->get());
+ }
+ }
GetClassLinker()->AddExtraBootDexFiles(Thread::Current(), std::move(dex_files));
}
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 395128d003..a932718ab1 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -302,11 +302,24 @@ class Runtime {
return boot_class_path_locations_.empty() ? boot_class_path_ : boot_class_path_locations_;
}
- // Dynamically add an element to boot class path.
+ // Dynamically adds an element to boot class path.
void AppendToBootClassPath(const std::string& filename,
const std::string& location,
const std::vector<std::unique_ptr<const art::DexFile>>& dex_files);
+ // Same as above, but takes raw pointers.
+ void AppendToBootClassPath(const std::string& filename,
+ const std::string& location,
+ const std::vector<const art::DexFile*>& dex_files);
+
+ // Same as above, but also takes a dex cache for each dex file.
+ void AppendToBootClassPath(
+ const std::string& filename,
+ const std::string& location,
+ const std::vector<std::pair<const art::DexFile*, ObjPtr<mirror::DexCache>>>&
+ dex_files_and_cache);
+
+ // Dynamically adds an element to boot class path and takes ownership of the dex files.
void AddExtraBootDexFiles(const std::string& filename,
const std::string& location,
std::vector<std::unique_ptr<const art::DexFile>>&& dex_files);
@@ -1156,6 +1169,8 @@ class Runtime {
// Caches the apex versions produced by `GetApexVersions`.
void InitializeApexVersions();
+ void AppendToBootClassPath(const std::string& filename, const std::string& location);
+
// A pointer to the active runtime or null.
static Runtime* instance_;