lin
2025-07-31 065ea569db06206874bbfa18eb25ff6121aec09b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
#ifndef ART_RUNTIME_VERIFIER_VERIFIER_DEPS_H_
#define ART_RUNTIME_VERIFIER_VERIFIER_DEPS_H_
 
#include <map>
#include <set>
#include <vector>
 
#include "base/array_ref.h"
#include "base/locks.h"
#include "dex/dex_file_structs.h"
#include "dex/dex_file_types.h"
#include "handle.h"
#include "obj_ptr.h"
#include "thread.h"
#include "verifier_enums.h"  // For MethodVerifier::FailureKind.
 
namespace art {
 
class ArtField;
class ArtMethod;
class DexFile;
class VariableIndentationOutputStream;
 
namespace mirror {
class Class;
class ClassLoader;
}  // namespace mirror
 
namespace verifier {
 
// Verification dependencies collector class used by the MethodVerifier to record
// resolution outcomes and type assignability tests of classes/methods/fields
// not present in the set of compiled DEX files, that is classes/methods/fields
// defined in the classpath.
// The compilation driver initializes the class and registers all DEX files
// which are being compiled. Classes defined in DEX files outside of this set
// (or synthesized classes without associated DEX files) are considered being
// in the classpath.
// During code-flow verification, the MethodVerifier informs VerifierDeps
// about the outcome of every resolution and assignability test, and
// the VerifierDeps object records them if their outcome may change with
// changes in the classpath.
class VerifierDeps {
 public:
  explicit VerifierDeps(const std::vector<const DexFile*>& dex_files);
 
  VerifierDeps(const std::vector<const DexFile*>& dex_files, ArrayRef<const uint8_t> data);
 
  // Merge `other` into this `VerifierDeps`'. `other` and `this` must be for the
  // same set of dex files.
  void MergeWith(std::unique_ptr<VerifierDeps> other, const std::vector<const DexFile*>& dex_files);
 
  // Record information that a class was verified.
  // Note that this function is different from MaybeRecordVerificationStatus() which
  // looks up thread-local VerifierDeps first.
  void RecordClassVerified(const DexFile& dex_file, const dex::ClassDef& class_def)
      REQUIRES(!Locks::verifier_deps_lock_);
 
  // Record the verification status of the class defined in `class_def`.
  static void MaybeRecordVerificationStatus(const DexFile& dex_file,
                                            const dex::ClassDef& class_def,
                                            FailureKind failure_kind)
      REQUIRES(!Locks::verifier_deps_lock_);
 
  // Record that class defined in `class_def` was not verified because it redefines
  // a class with the same descriptor which takes precedence in class resolution.
  static void MaybeRecordClassRedefinition(const DexFile& dex_file, const dex::ClassDef& class_def)
      REQUIRES(!Locks::verifier_deps_lock_);
 
  // Record the outcome `klass` of resolving type `type_idx` from `dex_file`.
  // If `klass` is null, the class is assumed unresolved.
  static void MaybeRecordClassResolution(const DexFile& dex_file,
                                         dex::TypeIndex type_idx,
                                         ObjPtr<mirror::Class> klass)
      REQUIRES_SHARED(Locks::mutator_lock_)
      REQUIRES(!Locks::verifier_deps_lock_);
 
  // Record the outcome `field` of resolving field `field_idx` from `dex_file`.
  // If `field` is null, the field is assumed unresolved.
  static void MaybeRecordFieldResolution(const DexFile& dex_file,
                                         uint32_t field_idx,
                                         ArtField* field)
      REQUIRES_SHARED(Locks::mutator_lock_)
      REQUIRES(!Locks::verifier_deps_lock_);
 
  // Record the outcome `method` of resolving method `method_idx` from `dex_file`.
  // If `method` is null, the method is assumed unresolved.
  static void MaybeRecordMethodResolution(const DexFile& dex_file,
                                          uint32_t method_idx,
                                          ArtMethod* method)
      REQUIRES_SHARED(Locks::mutator_lock_)
      REQUIRES(!Locks::verifier_deps_lock_);
 
  // Record the outcome `is_assignable` of type assignability test from `source`
  // to `destination` as defined by RegType::AssignableFrom. `dex_file` is the
  // owner of the method for which MethodVerifier performed the assignability test.
  static void MaybeRecordAssignability(const DexFile& dex_file,
                                       ObjPtr<mirror::Class> destination,
                                       ObjPtr<mirror::Class> source,
                                       bool is_strict,
                                       bool is_assignable)
      REQUIRES_SHARED(Locks::mutator_lock_)
      REQUIRES(!Locks::verifier_deps_lock_);
 
  // Serialize the recorded dependencies and store the data into `buffer`.
  // `dex_files` provides the order of the dex files in which the dependencies
  // should be emitted.
  void Encode(const std::vector<const DexFile*>& dex_files, std::vector<uint8_t>* buffer) const;
 
  void Dump(VariableIndentationOutputStream* vios) const;
 
  // Verify the encoded dependencies of this `VerifierDeps` are still valid.
  bool ValidateDependencies(Thread* self,
                            Handle<mirror::ClassLoader> class_loader,
                            const std::vector<const DexFile*>& classpath,
                            /* out */ std::string* error_msg) const
      REQUIRES_SHARED(Locks::mutator_lock_);
 
  const std::vector<bool>& GetVerifiedClasses(const DexFile& dex_file) const {
    return GetDexFileDeps(dex_file)->verified_classes_;
  }
 
  const std::vector<bool>& GetRedefinedClasses(const DexFile& dex_file) const {
    return GetDexFileDeps(dex_file)->redefined_classes_;
  }
 
  bool OutputOnly() const {
    return output_only_;
  }
 
  // Parses raw VerifierDeps data to extract bitvectors of which class def indices
  // were verified or not. The given `dex_files` must match the order and count of
  // dex files used to create the VerifierDeps.
  static std::vector<std::vector<bool>> ParseVerifiedClasses(
      const std::vector<const DexFile*>& dex_files,
      ArrayRef<const uint8_t> data);
 
 private:
  static constexpr uint16_t kUnresolvedMarker = static_cast<uint16_t>(-1);
 
  using ClassResolutionBase = std::tuple<dex::TypeIndex, uint16_t>;
  struct ClassResolution : public ClassResolutionBase {
    ClassResolution() = default;
    ClassResolution(const ClassResolution&) = default;
    ClassResolution(dex::TypeIndex type_idx, uint16_t access_flags)
        : ClassResolutionBase(type_idx, access_flags) {}
 
    bool IsResolved() const { return GetAccessFlags() != kUnresolvedMarker; }
    dex::TypeIndex GetDexTypeIndex() const { return std::get<0>(*this); }
    uint16_t GetAccessFlags() const { return std::get<1>(*this); }
  };
 
  using FieldResolutionBase = std::tuple<uint32_t, uint16_t, dex::StringIndex>;
  struct FieldResolution : public FieldResolutionBase {
    FieldResolution() = default;
    FieldResolution(const FieldResolution&) = default;
    FieldResolution(uint32_t field_idx, uint16_t access_flags, dex::StringIndex declaring_class_idx)
        : FieldResolutionBase(field_idx, access_flags, declaring_class_idx) {}
 
    bool IsResolved() const { return GetAccessFlags() != kUnresolvedMarker; }
    uint32_t GetDexFieldIndex() const { return std::get<0>(*this); }
    uint16_t GetAccessFlags() const { return std::get<1>(*this); }
    dex::StringIndex GetDeclaringClassIndex() const { return std::get<2>(*this); }
  };
 
  using MethodResolutionBase = std::tuple<uint32_t, uint16_t, dex::StringIndex>;
  struct MethodResolution : public MethodResolutionBase {
    MethodResolution() = default;
    MethodResolution(const MethodResolution&) = default;
    MethodResolution(uint32_t method_idx,
                     uint16_t access_flags,
                     dex::StringIndex declaring_class_idx)
        : MethodResolutionBase(method_idx, access_flags, declaring_class_idx) {}
 
    bool IsResolved() const { return GetAccessFlags() != kUnresolvedMarker; }
    uint32_t GetDexMethodIndex() const { return std::get<0>(*this); }
    uint16_t GetAccessFlags() const { return std::get<1>(*this); }
    dex::StringIndex GetDeclaringClassIndex() const { return std::get<2>(*this); }
  };
 
  using TypeAssignabilityBase = std::tuple<dex::StringIndex, dex::StringIndex>;
  struct TypeAssignability : public TypeAssignabilityBase {
    TypeAssignability() = default;
    TypeAssignability(const TypeAssignability&) = default;
    TypeAssignability(dex::StringIndex destination_idx, dex::StringIndex source_idx)
        : TypeAssignabilityBase(destination_idx, source_idx) {}
 
    dex::StringIndex GetDestination() const { return std::get<0>(*this); }
    dex::StringIndex GetSource() const { return std::get<1>(*this); }
  };
 
  // Data structure representing dependencies collected during verification of
  // methods inside one DexFile.
  struct DexFileDeps {
    explicit DexFileDeps(size_t num_class_defs)
        : verified_classes_(num_class_defs),
          redefined_classes_(num_class_defs) {}
 
    // Vector of strings which are not present in the corresponding DEX file.
    // These are referred to with ids starting with `NumStringIds()` of that DexFile.
    std::vector<std::string> strings_;
 
    // Set of class pairs recording the outcome of assignability test from one
    // of the two types to the other.
    std::set<TypeAssignability> assignable_types_;
    std::set<TypeAssignability> unassignable_types_;
 
    // Sets of recorded class/field/method resolutions.
    std::set<ClassResolution> classes_;
    std::set<FieldResolution> fields_;
    std::set<MethodResolution> methods_;
 
    // Bit vector indexed by class def indices indicating whether the corresponding
    // class was successfully verified.
    std::vector<bool> verified_classes_;
 
    // Bit vector indexed by class def indices indicating whether the corresponding
    // class resolved into a different class with the same descriptor (was eclipsed).
    // The other class might have been both external (not covered by these VerifierDeps)
    // and internal (same VerifierDeps, different DexFileDeps).
    std::vector<bool> redefined_classes_;
 
    bool Equals(const DexFileDeps& rhs) const;
  };
 
  VerifierDeps(const std::vector<const DexFile*>& dex_files, bool output_only);
 
  // Helper function to share DexFileDeps decoding code.
  static void DecodeDexFileDeps(DexFileDeps& deps,
                                const uint8_t** data_start,
                                const uint8_t* data_end);
 
  // Finds the DexFileDep instance associated with `dex_file`, or nullptr if
  // `dex_file` is not reported as being compiled.
  DexFileDeps* GetDexFileDeps(const DexFile& dex_file);
 
  const DexFileDeps* GetDexFileDeps(const DexFile& dex_file) const;
 
  // Returns true if `klass` is null or not defined in any of dex files which
  // were reported as being compiled.
  bool IsInClassPath(ObjPtr<mirror::Class> klass) const
      REQUIRES_SHARED(Locks::mutator_lock_);
 
  // Finds the class in the classpath that makes `source` inherit` from `destination`.
  // Returns null if a class defined in the compiled DEX files, and assignable to
  // `source`, direclty inherits from `destination`.
  ObjPtr<mirror::Class> FindOneClassPathBoundaryForInterface(ObjPtr<mirror::Class> destination,
                                                             ObjPtr<mirror::Class> source) const
      REQUIRES_SHARED(Locks::mutator_lock_);
 
  // Returns the index of `str`. If it is defined in `dex_file_`, this is the dex
  // string ID. If not, an ID is assigned to the string and cached in `strings_`
  // of the corresponding DexFileDeps structure (either provided or inferred from
  // `dex_file`).
  dex::StringIndex GetIdFromString(const DexFile& dex_file, const std::string& str)
      REQUIRES(!Locks::verifier_deps_lock_);
 
  // Returns the string represented by `id`.
  std::string GetStringFromId(const DexFile& dex_file, dex::StringIndex string_id) const;
 
  // Returns the bytecode access flags of `element` (bottom 16 bits), or
  // `kUnresolvedMarker` if `element` is null.
  template <typename Ptr>
  static uint16_t GetAccessFlags(Ptr element)
      REQUIRES_SHARED(Locks::mutator_lock_);
 
  // Returns a string ID of the descriptor of the declaring class of `element`,
  // or `kUnresolvedMarker` if `element` is null.
  dex::StringIndex GetMethodDeclaringClassStringId(const DexFile& dex_file,
                                                   uint32_t dex_method_idx,
                                                   ArtMethod* method)
      REQUIRES_SHARED(Locks::mutator_lock_);
  dex::StringIndex GetFieldDeclaringClassStringId(const DexFile& dex_file,
                                                  uint32_t dex_field_idx,
                                                  ArtField* field)
      REQUIRES_SHARED(Locks::mutator_lock_);
 
  // Returns a string ID of the descriptor of the class.
  dex::StringIndex GetClassDescriptorStringId(const DexFile& dex_file, ObjPtr<mirror::Class> klass)
      REQUIRES_SHARED(Locks::mutator_lock_)
      REQUIRES(!Locks::verifier_deps_lock_);
 
  void AddClassResolution(const DexFile& dex_file,
                          dex::TypeIndex type_idx,
                          ObjPtr<mirror::Class> klass)
      REQUIRES_SHARED(Locks::mutator_lock_)
      REQUIRES(!Locks::verifier_deps_lock_);
 
  void AddFieldResolution(const DexFile& dex_file,
                          uint32_t field_idx,
                          ArtField* field)
      REQUIRES_SHARED(Locks::mutator_lock_)
      REQUIRES(!Locks::verifier_deps_lock_);
 
  void AddMethodResolution(const DexFile& dex_file,
                           uint32_t method_idx,
                           ArtMethod* method)
      REQUIRES_SHARED(Locks::mutator_lock_)
      REQUIRES(!Locks::verifier_deps_lock_);
 
  void AddAssignability(const DexFile& dex_file,
                        ObjPtr<mirror::Class> destination,
                        ObjPtr<mirror::Class> source,
                        bool is_strict,
                        bool is_assignable)
      REQUIRES_SHARED(Locks::mutator_lock_);
 
  bool Equals(const VerifierDeps& rhs) const;
 
  // Verify `dex_file` according to the `deps`, that is going over each
  // `DexFileDeps` field, and checking that the recorded information still
  // holds.
  bool VerifyDexFile(Handle<mirror::ClassLoader> class_loader,
                     const DexFile& dex_file,
                     const DexFileDeps& deps,
                     const std::vector<const DexFile*>& classpath,
                     Thread* self,
                     /* out */ std::string* error_msg) const
      REQUIRES_SHARED(Locks::mutator_lock_);
 
  // Iterates over `dex_files` and tries to find a class def matching `descriptor`.
  // Returns true if such class def is found.
  bool IsInDexFiles(const char* descriptor,
                    size_t hash,
                    const std::vector<const DexFile*>& dex_files,
                    /* out */ const DexFile** cp_dex_file) const;
 
  // Check that classes which are to be verified using these dependencies
  // are not eclipsed by classes in parent class loaders, e.g. when vdex was
  // created against SDK stubs and the app redefines a non-public class on
  // boot classpath, or simply if a class is added during an OTA. In such cases,
  // dependencies do not include the dependencies on the presumed-internal class
  // and verification must fail unless the class was recorded to have been
  // redefined during dependencies' generation too.
  bool VerifyInternalClasses(const DexFile& dex_file,
                             const std::vector<const DexFile*>& classpath,
                             const std::vector<bool>& verified_classes,
                             const std::vector<bool>& redefined_classes,
                             /* out */ std::string* error_msg) const
      REQUIRES_SHARED(Locks::mutator_lock_);
 
  bool VerifyAssignability(Handle<mirror::ClassLoader> class_loader,
                           const DexFile& dex_file,
                           const std::set<TypeAssignability>& assignables,
                           bool expected_assignability,
                           Thread* self,
                           /* out */ std::string* error_msg) const
      REQUIRES_SHARED(Locks::mutator_lock_);
 
  // Verify that the set of resolved classes at the point of creation
  // of this `VerifierDeps` is still the same.
  bool VerifyClasses(Handle<mirror::ClassLoader> class_loader,
                     const DexFile& dex_file,
                     const std::set<ClassResolution>& classes,
                     Thread* self,
                     /* out */ std::string* error_msg) const
      REQUIRES_SHARED(Locks::mutator_lock_);
 
  // Verify that the set of resolved fields at the point of creation
  // of this `VerifierDeps` is still the same, and each field resolves to the
  // same field holder and access flags.
  bool VerifyFields(Handle<mirror::ClassLoader> class_loader,
                    const DexFile& dex_file,
                    const std::set<FieldResolution>& classes,
                    Thread* self,
                    /* out */ std::string* error_msg) const
      REQUIRES_SHARED(Locks::mutator_lock_)
      REQUIRES(!Locks::verifier_deps_lock_);
 
  // Verify that the set of resolved methods at the point of creation
  // of this `VerifierDeps` is still the same, and each method resolves to the
  // same method holder, access flags, and invocation kind.
  bool VerifyMethods(Handle<mirror::ClassLoader> class_loader,
                     const DexFile& dex_file,
                     const std::set<MethodResolution>& methods,
                     Thread* self,
                     /* out */ std::string* error_msg) const
      REQUIRES_SHARED(Locks::mutator_lock_);
 
  // Map from DexFiles into dependencies collected from verification of their methods.
  std::map<const DexFile*, std::unique_ptr<DexFileDeps>> dex_deps_;
 
  // Output only signifies if we are using the verifier deps to verify or just to generate them.
  const bool output_only_;
 
  friend class VerifierDepsTest;
  ART_FRIEND_TEST(VerifierDepsTest, StringToId);
  ART_FRIEND_TEST(VerifierDepsTest, EncodeDecode);
  ART_FRIEND_TEST(VerifierDepsTest, EncodeDecodeMulti);
  ART_FRIEND_TEST(VerifierDepsTest, VerifyDeps);
  ART_FRIEND_TEST(VerifierDepsTest, CompilerDriver);
};
 
}  // namespace verifier
}  // namespace art
 
#endif  // ART_RUNTIME_VERIFIER_VERIFIER_DEPS_H_