diff options
author | 2022-08-25 14:03:26 +0100 | |
---|---|---|
committer | 2022-09-05 12:24:25 +0100 | |
commit | 28451dc19280f0c1991f9af6f3c087f3ec08de79 (patch) | |
tree | 2e4123d8648c147618d2b0bc4761277a9e3a073f | |
parent | 94383b4038970838ded1f0a482f16d8b612a4701 (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.h | 13 | ||||
-rw-r--r-- | openjdkjvmti/ti_class_loader.cc | 3 | ||||
-rw-r--r-- | openjdkjvmti/ti_redefine.cc | 13 | ||||
-rw-r--r-- | runtime/class_linker.h | 3 | ||||
-rw-r--r-- | runtime/runtime.cc | 59 | ||||
-rw-r--r-- | runtime/runtime.h | 17 |
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_; |