Chang Xing | 605fe24 | 2017-07-20 15:57:21 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2017 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include "aot_class_linker.h" |
| 18 | |
Andreas Gampe | 5d3b002 | 2017-08-31 10:36:31 -0700 | [diff] [blame] | 19 | #include "class_status.h" |
Mathieu Chartier | 9e050df | 2017-08-09 10:05:47 -0700 | [diff] [blame] | 20 | #include "compiler_callbacks.h" |
David Sehr | 312f3b2 | 2018-03-19 08:39:26 -0700 | [diff] [blame] | 21 | #include "dex/class_reference.h" |
Vladimir Marko | 7ed2d38 | 2019-11-25 10:41:53 +0000 | [diff] [blame] | 22 | #include "gc/heap.h" |
Chang Xing | 605fe24 | 2017-07-20 15:57:21 -0700 | [diff] [blame] | 23 | #include "handle_scope-inl.h" |
Mathieu Chartier | 9e050df | 2017-08-09 10:05:47 -0700 | [diff] [blame] | 24 | #include "mirror/class-inl.h" |
Chang Xing | 605fe24 | 2017-07-20 15:57:21 -0700 | [diff] [blame] | 25 | #include "runtime.h" |
Mathieu Chartier | 9e050df | 2017-08-09 10:05:47 -0700 | [diff] [blame] | 26 | #include "verifier/verifier_enums.h" |
Chang Xing | 605fe24 | 2017-07-20 15:57:21 -0700 | [diff] [blame] | 27 | |
| 28 | namespace art { |
| 29 | |
Andreas Gampe | 87658f3 | 2019-04-18 18:39:02 +0000 | [diff] [blame] | 30 | AotClassLinker::AotClassLinker(InternTable* intern_table) |
| 31 | : ClassLinker(intern_table, /*fast_class_not_found_exceptions=*/ false) {} |
Chang Xing | 605fe24 | 2017-07-20 15:57:21 -0700 | [diff] [blame] | 32 | |
| 33 | AotClassLinker::~AotClassLinker() {} |
| 34 | |
Chang Xing | 0c2c222 | 2017-08-04 14:36:17 -0700 | [diff] [blame] | 35 | bool AotClassLinker::CanAllocClass() { |
| 36 | // AllocClass doesn't work under transaction, so we abort. |
| 37 | if (Runtime::Current()->IsActiveTransaction()) { |
| 38 | Runtime::Current()->AbortTransactionAndThrowAbortError( |
| 39 | Thread::Current(), "Can't resolve type within transaction."); |
| 40 | return false; |
| 41 | } |
| 42 | return ClassLinker::CanAllocClass(); |
| 43 | } |
| 44 | |
Chang Xing | 605fe24 | 2017-07-20 15:57:21 -0700 | [diff] [blame] | 45 | // Wrap the original InitializeClass with creation of transaction when in strict mode. |
Vladimir Marko | 4617d58 | 2019-03-28 13:48:31 +0000 | [diff] [blame] | 46 | bool AotClassLinker::InitializeClass(Thread* self, |
| 47 | Handle<mirror::Class> klass, |
| 48 | bool can_init_statics, |
| 49 | bool can_init_parents) { |
Chang Xing | 605fe24 | 2017-07-20 15:57:21 -0700 | [diff] [blame] | 50 | Runtime* const runtime = Runtime::Current(); |
Vladimir Marko | 889b72d | 2019-11-12 11:01:13 +0000 | [diff] [blame] | 51 | bool strict_mode = runtime->IsActiveStrictTransactionMode(); |
Chang Xing | 605fe24 | 2017-07-20 15:57:21 -0700 | [diff] [blame] | 52 | |
| 53 | DCHECK(klass != nullptr); |
| 54 | if (klass->IsInitialized() || klass->IsInitializing()) { |
| 55 | return ClassLinker::InitializeClass(self, klass, can_init_statics, can_init_parents); |
| 56 | } |
| 57 | |
Vladimir Marko | 889b72d | 2019-11-12 11:01:13 +0000 | [diff] [blame] | 58 | // When compiling a boot image extension, do not initialize a class defined |
| 59 | // in a dex file belonging to the boot image we're compiling against. |
| 60 | // However, we must allow the initialization of TransactionAbortError, |
| 61 | // VerifyError, etc. outside of a transaction. |
| 62 | if (!strict_mode && runtime->GetHeap()->ObjectIsInBootImageSpace(klass->GetDexCache())) { |
| 63 | if (runtime->IsActiveTransaction()) { |
| 64 | runtime->AbortTransactionAndThrowAbortError(self, "Can't initialize " + klass->PrettyTypeOf() |
| 65 | + " because it is defined in a boot image dex file."); |
| 66 | return false; |
| 67 | } |
| 68 | CHECK(klass->IsThrowableClass()) << klass->PrettyDescriptor(); |
| 69 | } |
| 70 | |
Chang Xing | 0c2c222 | 2017-08-04 14:36:17 -0700 | [diff] [blame] | 71 | // When in strict_mode, don't initialize a class if it belongs to boot but not initialized. |
Vladimir Marko | 889b72d | 2019-11-12 11:01:13 +0000 | [diff] [blame] | 72 | if (strict_mode && klass->IsBootStrapClassLoaded()) { |
Chang Xing | 0c2c222 | 2017-08-04 14:36:17 -0700 | [diff] [blame] | 73 | runtime->AbortTransactionAndThrowAbortError(self, "Can't resolve " |
| 74 | + klass->PrettyTypeOf() + " because it is an uninitialized boot class."); |
| 75 | return false; |
| 76 | } |
| 77 | |
Chang Xing | adbb91c | 2017-07-17 11:23:55 -0700 | [diff] [blame] | 78 | // Don't initialize klass if it's superclass is not initialized, because superclass might abort |
| 79 | // the transaction and rolled back after klass's change is commited. |
Vladimir Marko | 889b72d | 2019-11-12 11:01:13 +0000 | [diff] [blame] | 80 | if (strict_mode && !klass->IsInterface() && klass->HasSuperClass()) { |
Vladimir Marko | 2c64a83 | 2018-01-04 11:31:56 +0000 | [diff] [blame] | 81 | if (klass->GetSuperClass()->GetStatus() == ClassStatus::kInitializing) { |
Chang Xing | adbb91c | 2017-07-17 11:23:55 -0700 | [diff] [blame] | 82 | runtime->AbortTransactionAndThrowAbortError(self, "Can't resolve " |
| 83 | + klass->PrettyTypeOf() + " because it's superclass is not initialized."); |
| 84 | return false; |
| 85 | } |
| 86 | } |
| 87 | |
Vladimir Marko | 889b72d | 2019-11-12 11:01:13 +0000 | [diff] [blame] | 88 | if (strict_mode) { |
Vladimir Marko | 672c080 | 2019-07-26 13:03:13 +0100 | [diff] [blame] | 89 | runtime->EnterTransactionMode(/*strict=*/ true, klass.Get()); |
Chang Xing | 605fe24 | 2017-07-20 15:57:21 -0700 | [diff] [blame] | 90 | } |
| 91 | bool success = ClassLinker::InitializeClass(self, klass, can_init_statics, can_init_parents); |
| 92 | |
Vladimir Marko | 889b72d | 2019-11-12 11:01:13 +0000 | [diff] [blame] | 93 | if (strict_mode) { |
Chang Xing | 605fe24 | 2017-07-20 15:57:21 -0700 | [diff] [blame] | 94 | if (success) { |
| 95 | // Exit Transaction if success. |
| 96 | runtime->ExitTransactionMode(); |
| 97 | } else { |
Chang Xing | 0c2c222 | 2017-08-04 14:36:17 -0700 | [diff] [blame] | 98 | // If not successfully initialized, don't rollback immediately, leave the cleanup to compiler |
| 99 | // driver which needs abort message and exception. |
Chang Xing | 605fe24 | 2017-07-20 15:57:21 -0700 | [diff] [blame] | 100 | DCHECK(self->IsExceptionPending()); |
| 101 | } |
| 102 | } |
| 103 | return success; |
| 104 | } |
Mathieu Chartier | 9e050df | 2017-08-09 10:05:47 -0700 | [diff] [blame] | 105 | |
Nicolas Geoffray | 5b0b2e1 | 2021-03-19 14:48:40 +0000 | [diff] [blame] | 106 | verifier::FailureKind AotClassLinker::PerformClassVerification( |
| 107 | Thread* self, |
| 108 | verifier::VerifierDeps* verifier_deps, |
| 109 | Handle<mirror::Class> klass, |
| 110 | verifier::HardFailLogMode log_level, |
| 111 | std::string* error_msg) { |
Mathieu Chartier | 9e050df | 2017-08-09 10:05:47 -0700 | [diff] [blame] | 112 | Runtime* const runtime = Runtime::Current(); |
| 113 | CompilerCallbacks* callbacks = runtime->GetCompilerCallbacks(); |
Andreas Gampe | 5d3b002 | 2017-08-31 10:36:31 -0700 | [diff] [blame] | 114 | ClassStatus old_status = callbacks->GetPreviousClassState( |
| 115 | ClassReference(&klass->GetDexFile(), klass->GetDexClassDefIndex())); |
Andreas Gampe | d3ea5b3 | 2017-09-04 14:55:34 -0700 | [diff] [blame] | 116 | // Was it verified? Report no failure. |
Vladimir Marko | 2c64a83 | 2018-01-04 11:31:56 +0000 | [diff] [blame] | 117 | if (old_status >= ClassStatus::kVerified) { |
Mathieu Chartier | 9e050df | 2017-08-09 10:05:47 -0700 | [diff] [blame] | 118 | return verifier::FailureKind::kNoFailure; |
| 119 | } |
Nicolas Geoffray | 1715efa | 2020-06-05 18:34:49 +0100 | [diff] [blame] | 120 | if (old_status >= ClassStatus::kVerifiedNeedsAccessChecks) { |
| 121 | return verifier::FailureKind::kAccessChecksFailure; |
| 122 | } |
Andreas Gampe | d3ea5b3 | 2017-09-04 14:55:34 -0700 | [diff] [blame] | 123 | // Does it need to be verified at runtime? Report soft failure. |
Vladimir Marko | 2c64a83 | 2018-01-04 11:31:56 +0000 | [diff] [blame] | 124 | if (old_status >= ClassStatus::kRetryVerificationAtRuntime) { |
Andreas Gampe | d3ea5b3 | 2017-09-04 14:55:34 -0700 | [diff] [blame] | 125 | // Error messages from here are only reported through -verbose:class. It is not worth it to |
| 126 | // create a message. |
| 127 | return verifier::FailureKind::kSoftFailure; |
| 128 | } |
| 129 | // Do the actual work. |
Nicolas Geoffray | 5b0b2e1 | 2021-03-19 14:48:40 +0000 | [diff] [blame] | 130 | return ClassLinker::PerformClassVerification(self, verifier_deps, klass, log_level, error_msg); |
Mathieu Chartier | 9e050df | 2017-08-09 10:05:47 -0700 | [diff] [blame] | 131 | } |
| 132 | |
Vladimir Marko | 7ed2d38 | 2019-11-25 10:41:53 +0000 | [diff] [blame] | 133 | bool AotClassLinker::CanReferenceInBootImageExtension(ObjPtr<mirror::Class> klass, gc::Heap* heap) { |
| 134 | // Do not allow referencing a class or instance of a class defined in a dex file |
| 135 | // belonging to the boot image we're compiling against but not itself in the boot image; |
| 136 | // or a class referencing such classes as component type, superclass or interface. |
| 137 | // Allowing this could yield duplicate class objects from multiple extensions. |
| 138 | |
| 139 | if (heap->ObjectIsInBootImageSpace(klass)) { |
| 140 | return true; // Already included in the boot image we're compiling against. |
| 141 | } |
| 142 | |
| 143 | // Treat arrays and primitive types specially because they do not have a DexCache that we |
| 144 | // can use to check whether the dex file belongs to the boot image we're compiling against. |
| 145 | DCHECK(!klass->IsPrimitive()); // Primitive classes must be in the primary boot image. |
| 146 | if (klass->IsArrayClass()) { |
| 147 | DCHECK(heap->ObjectIsInBootImageSpace(klass->GetIfTable())); // IfTable is OK. |
| 148 | // Arrays of all dimensions are tied to the dex file of the non-array component type. |
| 149 | do { |
| 150 | klass = klass->GetComponentType(); |
| 151 | } while (klass->IsArrayClass()); |
| 152 | if (klass->IsPrimitive()) { |
| 153 | return false; |
| 154 | } |
| 155 | // Do not allow arrays of erroneous classes (the array class is not itself erroneous). |
| 156 | if (klass->IsErroneous()) { |
| 157 | return false; |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | // Check the class itself. |
| 162 | if (heap->ObjectIsInBootImageSpace(klass->GetDexCache())) { |
| 163 | return false; |
| 164 | } |
| 165 | |
| 166 | // Check superclasses. |
| 167 | ObjPtr<mirror::Class> superclass = klass->GetSuperClass(); |
| 168 | while (!heap->ObjectIsInBootImageSpace(superclass)) { |
| 169 | DCHECK(superclass != nullptr); // Cannot skip Object which is in the primary boot image. |
| 170 | if (heap->ObjectIsInBootImageSpace(superclass->GetDexCache())) { |
| 171 | return false; |
| 172 | } |
| 173 | superclass = superclass->GetSuperClass(); |
| 174 | } |
| 175 | |
| 176 | // Check IfTable. This includes direct and indirect interfaces. |
| 177 | ObjPtr<mirror::IfTable> if_table = klass->GetIfTable(); |
| 178 | for (size_t i = 0, num_interfaces = klass->GetIfTableCount(); i < num_interfaces; ++i) { |
| 179 | ObjPtr<mirror::Class> interface = if_table->GetInterface(i); |
| 180 | DCHECK(interface != nullptr); |
| 181 | if (!heap->ObjectIsInBootImageSpace(interface) && |
| 182 | heap->ObjectIsInBootImageSpace(interface->GetDexCache())) { |
| 183 | return false; |
| 184 | } |
| 185 | } |
| 186 | |
| 187 | if (kIsDebugBuild) { |
| 188 | // All virtual methods must come from classes we have already checked above. |
| 189 | PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); |
| 190 | ObjPtr<mirror::Class> k = klass; |
| 191 | while (!heap->ObjectIsInBootImageSpace(k)) { |
| 192 | for (auto& m : k->GetVirtualMethods(pointer_size)) { |
| 193 | ObjPtr<mirror::Class> declaring_class = m.GetDeclaringClass(); |
| 194 | CHECK(heap->ObjectIsInBootImageSpace(declaring_class) || |
| 195 | !heap->ObjectIsInBootImageSpace(declaring_class->GetDexCache())); |
| 196 | } |
| 197 | k = k->GetSuperClass(); |
| 198 | } |
| 199 | } |
| 200 | |
| 201 | return true; |
| 202 | } |
| 203 | |
Vladimir Marko | d1f7351 | 2020-04-02 10:50:35 +0100 | [diff] [blame] | 204 | bool AotClassLinker::SetUpdatableBootClassPackages(const std::vector<std::string>& packages) { |
| 205 | DCHECK(updatable_boot_class_path_descriptor_prefixes_.empty()); |
| 206 | // Transform package names to descriptor prefixes. |
| 207 | std::vector<std::string> prefixes; |
| 208 | prefixes.reserve(packages.size()); |
| 209 | for (const std::string& package : packages) { |
| 210 | if (package.empty() || package.find('/') != std::string::npos) { |
| 211 | LOG(ERROR) << "Invalid package name: " << package; |
| 212 | return false; |
| 213 | } |
| 214 | std::string prefix = 'L' + package + '/'; |
| 215 | std::replace(prefix.begin(), prefix.end(), '.', '/'); |
| 216 | prefixes.push_back(std::move(prefix)); |
| 217 | } |
| 218 | // Sort and remove unnecessary prefixes. |
| 219 | std::sort(prefixes.begin(), prefixes.end()); |
| 220 | std::string last_prefix; |
| 221 | auto end_it = std::remove_if( |
| 222 | prefixes.begin(), |
| 223 | prefixes.end(), |
| 224 | [&last_prefix](const std::string& s) { |
| 225 | if (!last_prefix.empty() && StartsWith(s, last_prefix)) { |
| 226 | return true; |
| 227 | } else { |
| 228 | last_prefix = s; |
| 229 | return false; |
| 230 | } |
| 231 | }); |
| 232 | prefixes.resize(std::distance(prefixes.begin(), end_it)); |
| 233 | prefixes.shrink_to_fit(); |
| 234 | updatable_boot_class_path_descriptor_prefixes_.swap(prefixes); |
| 235 | return true; |
| 236 | } |
| 237 | |
| 238 | bool AotClassLinker::IsUpdatableBootClassPathDescriptor(const char* descriptor) { |
| 239 | std::string_view descriptor_sv(descriptor); |
| 240 | for (const std::string& prefix : updatable_boot_class_path_descriptor_prefixes_) { |
| 241 | if (StartsWith(descriptor_sv, prefix)) { |
| 242 | return true; |
| 243 | } |
| 244 | } |
| 245 | return false; |
| 246 | } |
Calin Juravle | 3378768 | 2019-07-26 14:27:18 -0700 | [diff] [blame] | 247 | void AotClassLinker::SetSdkChecker(std::unique_ptr<SdkChecker>&& sdk_checker) { |
| 248 | sdk_checker_ = std::move(sdk_checker); |
| 249 | } |
| 250 | |
| 251 | const SdkChecker* AotClassLinker::GetSdkChecker() const { |
| 252 | return sdk_checker_.get(); |
| 253 | } |
| 254 | |
| 255 | bool AotClassLinker::DenyAccessBasedOnPublicSdk(ArtMethod* art_method) const |
| 256 | REQUIRES_SHARED(Locks::mutator_lock_) { |
| 257 | return sdk_checker_ != nullptr && sdk_checker_->ShouldDenyAccess(art_method); |
| 258 | } |
| 259 | bool AotClassLinker::DenyAccessBasedOnPublicSdk(ArtField* art_field) const |
| 260 | REQUIRES_SHARED(Locks::mutator_lock_) { |
| 261 | return sdk_checker_ != nullptr && sdk_checker_->ShouldDenyAccess(art_field); |
| 262 | } |
| 263 | bool AotClassLinker::DenyAccessBasedOnPublicSdk(const char* type_descriptor) const { |
| 264 | return sdk_checker_ != nullptr && sdk_checker_->ShouldDenyAccess(type_descriptor); |
| 265 | } |
Vladimir Marko | d1f7351 | 2020-04-02 10:50:35 +0100 | [diff] [blame] | 266 | |
Calin Juravle | 2c2724c | 2021-01-14 19:54:23 -0800 | [diff] [blame] | 267 | void AotClassLinker::SetEnablePublicSdkChecks(bool enabled) { |
| 268 | if (sdk_checker_ != nullptr) { |
| 269 | sdk_checker_->SetEnabled(enabled); |
| 270 | } |
| 271 | } |
| 272 | |
Chang Xing | 605fe24 | 2017-07-20 15:57:21 -0700 | [diff] [blame] | 273 | } // namespace art |