xref: /aosp_15_r20/art/runtime/verifier/class_verifier.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1 /*
2  * Copyright (C) 2011 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 "class_verifier.h"
18 
19 #include <android-base/logging.h>
20 #include <android-base/stringprintf.h>
21 
22 #include "art_method-inl.h"
23 #include "base/locks.h"
24 #include "base/logging.h"
25 #include "base/pointer_size.h"
26 #include "base/systrace.h"
27 #include "base/utils.h"
28 #include "class_linker.h"
29 #include "compiler_callbacks.h"
30 #include "dex/class_accessor-inl.h"
31 #include "dex/class_reference.h"
32 #include "dex/descriptors_names.h"
33 #include "dex/dex_file-inl.h"
34 #include "handle.h"
35 #include "handle_scope-inl.h"
36 #include "method_verifier-inl.h"
37 #include "mirror/class-inl.h"
38 #include "mirror/dex_cache.h"
39 #include "runtime.h"
40 #include "thread.h"
41 #include "verifier_compiler_binding.h"
42 #include "verifier/method_verifier.h"
43 #include "verifier/reg_type_cache.h"
44 
45 namespace art HIDDEN {
46 namespace verifier {
47 
48 using android::base::StringPrintf;
49 
50 // We print a warning blurb about "dx --no-optimize" when we find monitor-locking issues. Make
51 // sure we only print this once.
52 static bool gPrintedDxMonitorText = false;
53 
UpdateMethodFlags(uint32_t method_index,Handle<mirror::Class> klass,Handle<mirror::DexCache> dex_cache,CompilerCallbacks * callbacks,int error_types)54 static void UpdateMethodFlags(uint32_t method_index,
55                               Handle<mirror::Class> klass,
56                               Handle<mirror::DexCache> dex_cache,
57                               CompilerCallbacks* callbacks,
58                               int error_types)
59     REQUIRES_SHARED(Locks::mutator_lock_) {
60   if (callbacks != nullptr && !CanCompilerHandleVerificationFailure(error_types)) {
61     MethodReference ref(dex_cache->GetDexFile(), method_index);
62     callbacks->AddUncompilableMethod(ref);
63   }
64   if (klass == nullptr) {
65     DCHECK(Runtime::Current()->IsAotCompiler());
66     // Flags will be set at runtime.
67     return;
68   }
69 
70   // Mark methods with DontCompile/MustCountLocks flags.
71   ClassLinker* const linker = Runtime::Current()->GetClassLinker();
72   ArtMethod* method =
73       klass->FindClassMethod(dex_cache.Get(), method_index, linker->GetImagePointerSize());
74   DCHECK(method != nullptr);
75   DCHECK(method->GetDeclaringClass() == klass.Get());
76   if (!CanCompilerHandleVerificationFailure(error_types)) {
77     method->SetDontCompile();
78   }
79   if ((error_types & VerifyError::VERIFY_ERROR_LOCKING) != 0) {
80     method->SetMustCountLocks();
81   }
82 }
83 
VerifyClass(Thread * self,VerifierDeps * verifier_deps,const DexFile * dex_file,Handle<mirror::Class> klass,Handle<mirror::DexCache> dex_cache,Handle<mirror::ClassLoader> class_loader,const dex::ClassDef & class_def,CompilerCallbacks * callbacks,HardFailLogMode log_level,uint32_t api_level,std::string * error)84 FailureKind ClassVerifier::VerifyClass(Thread* self,
85                                        VerifierDeps* verifier_deps,
86                                        const DexFile* dex_file,
87                                        Handle<mirror::Class> klass,
88                                        Handle<mirror::DexCache> dex_cache,
89                                        Handle<mirror::ClassLoader> class_loader,
90                                        const dex::ClassDef& class_def,
91                                        CompilerCallbacks* callbacks,
92                                        HardFailLogMode log_level,
93                                        uint32_t api_level,
94                                        std::string* error) {
95   // A class must not be abstract and final.
96   if ((class_def.access_flags_ & (kAccAbstract | kAccFinal)) == (kAccAbstract | kAccFinal)) {
97     *error = "Verifier rejected class ";
98     *error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def));
99     *error += ": class is abstract and final.";
100     return FailureKind::kHardFailure;
101   }
102 
103   // Note that `klass` can be a redefined class, not in the loader's table yet.
104   // Therefore, we do not use it for class resolution, but only when needing to
105   // update its methods' flags.
106   ClassAccessor accessor(*dex_file, class_def);
107   SCOPED_TRACE << "VerifyClass " << PrettyDescriptor(accessor.GetDescriptor());
108   metrics::AutoTimer timer{GetMetrics()->ClassVerificationTotalTime()};
109 
110   int64_t previous_method_idx[2] = { -1, -1 };
111   MethodVerifier::FailureData failure_data;
112   ClassLinker* const linker = Runtime::Current()->GetClassLinker();
113 
114   if (accessor.NumMethods() != 0u) {
115     ArenaPool* arena_pool = Runtime::Current()->GetArenaPool();
116     RegTypeCache reg_types(self, linker, arena_pool, class_loader, dex_file);
117     for (const ClassAccessor::Method& method : accessor.GetMethods()) {
118       int64_t* previous_idx = &previous_method_idx[method.IsStaticOrDirect() ? 0u : 1u];
119       self->AllowThreadSuspension();
120       const uint32_t method_idx = method.GetIndex();
121       if (method_idx == *previous_idx) {
122         // smali can create dex files with two encoded_methods sharing the same method_idx
123         // http://code.google.com/p/smali/issues/detail?id=119
124         continue;
125       }
126       *previous_idx = method_idx;
127       std::string hard_failure_msg;
128       MethodVerifier::FailureData result =
129           MethodVerifier::VerifyMethod(self,
130                                        arena_pool,
131                                        &reg_types,
132                                        verifier_deps,
133                                        method_idx,
134                                        dex_cache,
135                                        class_def,
136                                        method.GetCodeItem(),
137                                        method.GetAccessFlags(),
138                                        log_level,
139                                        api_level,
140                                        Runtime::Current()->IsAotCompiler(),
141                                        &hard_failure_msg);
142       if (result.kind == FailureKind::kHardFailure) {
143         if (failure_data.kind == FailureKind::kHardFailure) {
144           // If we logged an error before, we need a newline.
145           *error += "\n";
146         } else {
147           // If we didn't log a hard failure before, print the header of the message.
148           *error += "Verifier rejected class ";
149           *error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def));
150           *error += ":";
151         }
152         *error += " ";
153         *error += hard_failure_msg;
154       } else if (result.kind != FailureKind::kNoFailure) {
155         UpdateMethodFlags(method.GetIndex(), klass, dex_cache, callbacks, result.types);
156         if ((result.types & VerifyError::VERIFY_ERROR_LOCKING) != 0) {
157           // Print a warning about expected slow-down.
158           // Use a string temporary to print one contiguous warning.
159           std::string tmp =
160               StringPrintf("Method %s failed lock verification and will run slower.",
161                            dex_file->PrettyMethod(method.GetIndex()).c_str());
162           if (!gPrintedDxMonitorText) {
163             tmp +=
164                 "\nCommon causes for lock verification issues are non-optimized dex code\n"
165                 "and incorrect proguard optimizations.";
166             gPrintedDxMonitorText = true;
167           }
168           LOG(WARNING) << tmp;
169         }
170       }
171 
172       // Merge the result for the method into the global state for the class.
173       failure_data.Merge(result);
174     }
175   }
176   uint64_t elapsed_time_microseconds = timer.Stop();
177   VLOG(verifier) << "VerifyClass took " << PrettyDuration(UsToNs(elapsed_time_microseconds))
178                  << ", class: " << PrettyDescriptor(dex_file->GetClassDescriptor(class_def));
179 
180   GetMetrics()->ClassVerificationCount()->AddOne();
181 
182   GetMetrics()->ClassVerificationTotalTimeDelta()->Add(elapsed_time_microseconds);
183   GetMetrics()->ClassVerificationCountDelta()->AddOne();
184 
185   if (failure_data.kind == verifier::FailureKind::kHardFailure && callbacks != nullptr) {
186     ClassReference ref(dex_file, dex_file->GetIndexForClassDef(class_def));
187     callbacks->ClassRejected(ref);
188   }
189 
190   return failure_data.kind;
191 }
192 
193 }  // namespace verifier
194 }  // namespace art
195