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
|
/*
* 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 "base/macros.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 HIDDEN {
class ArtField;
class ArtMethod;
class DexFile;
class VariableIndentationOutputStream;
namespace mirror {
class Class;
class ClassLoader;
} // namespace mirror
namespace verifier {
class RegType;
// 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:
EXPORT explicit VerifierDeps(const std::vector<const DexFile*>& dex_files,
bool output_only = true);
// Marker to know whether a class is verified. A non-verified class will have
// this marker as its offset entry in the encoded data.
static uint32_t constexpr kNotVerifiedMarker = std::numeric_limits<uint32_t>::max();
// Fill dependencies from stored data. Returns true on success, false on failure.
EXPORT bool ParseStoredData(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.
EXPORT 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`.
EXPORT static void MaybeRecordVerificationStatus(VerifierDeps* verifier_deps,
const DexFile& dex_file,
const dex::ClassDef& class_def,
FailureKind failure_kind)
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(VerifierDeps* verifier_deps,
const DexFile& dex_file,
const dex::ClassDef& class_def,
ObjPtr<mirror::Class> destination,
ObjPtr<mirror::Class> source)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::verifier_deps_lock_);
// Record that `source` is assignable to `destination`. `dex_file` is the
// owner of the method for which MethodVerifier performed the assignability test.
static void MaybeRecordAssignability(VerifierDeps* verifier_deps,
const DexFile& dex_file,
const dex::ClassDef& class_def,
const RegType& destination,
const RegType& source)
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.
EXPORT void Encode(const std::vector<const DexFile*>& dex_files,
std::vector<uint8_t>* buffer) const;
EXPORT void Dump(VariableIndentationOutputStream* vios) const;
// Verifies the encoded dependencies of this `VerifierDeps` are still valid.
// Returns whether all dependencies were validated.
EXPORT bool ValidateDependenciesAndUpdateStatus(
Thread* self,
Handle<mirror::ClassLoader> class_loader,
const std::vector<const DexFile*>& dex_files)
REQUIRES_SHARED(Locks::mutator_lock_);
const std::vector<bool>& GetVerifiedClasses(const DexFile& dex_file) const {
return GetDexFileDeps(dex_file)->verified_classes_;
}
// Whether this `verifier_deps` has recorded that the given class is verified.
bool HasRecordedVerifiedStatus(const DexFile& dex_file, const dex::ClassDef& class_def)
REQUIRES(!Locks::verifier_deps_lock_);
bool OutputOnly() const {
return output_only_;
}
bool ContainsDexFile(const DexFile& dex_file) const {
return GetDexFileDeps(dex_file) != nullptr;
}
// 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 bool ParseVerifiedClasses(
const std::vector<const DexFile*>& dex_files,
ArrayRef<const uint8_t> data,
/*out*/std::vector<std::vector<bool>>* verified_classes_per_dex);
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); }
};
private:
// Data structure representing dependencies collected during verification of
// methods inside one DexFile.
struct DexFileDeps {
explicit DexFileDeps(size_t num_class_defs)
: assignable_types_(num_class_defs),
verified_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_;
// Vector that contains for each class def defined in a dex file, a set of class pairs recording
// the outcome of assignability test from one of the two types to the other.
std::vector<std::set<TypeAssignability>> assignable_types_;
// Bit vector indexed by class def indices indicating whether the corresponding
// class was successfully verified.
std::vector<bool> verified_classes_;
bool Equals(const DexFileDeps& rhs) const;
};
// Helper function to share DexFileDeps decoding code.
// Returns true on success, false on failure.
template <bool kOnlyVerifiedClasses>
static bool DecodeDexFileDeps(DexFileDeps& deps,
const uint8_t** cursor,
const uint8_t* data_start,
const uint8_t* data_end,
size_t num_class_defs);
// 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);
EXPORT const DexFileDeps* GetDexFileDeps(const DexFile& dex_file) const;
// 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 `string_idx`.
const char* GetStringFromIndex(const DexFile& dex_file,
dex::StringIndex string_idx,
/*out*/ size_t* utf8_length = nullptr) const;
// 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 AddAssignability(const DexFile& dex_file,
const dex::ClassDef& class_def,
ObjPtr<mirror::Class> destination,
ObjPtr<mirror::Class> source)
REQUIRES_SHARED(Locks::mutator_lock_);
void AddAssignability(const DexFile& dex_file,
const dex::ClassDef& class_def,
const RegType& destination,
const RegType& source)
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.
// Returns whether all dependencies were validated.
bool VerifyDexFileAndUpdateStatus(
Handle<mirror::ClassLoader> class_loader,
const DexFile& dex_file,
DexFileDeps& deps,
Thread* self)
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;
// 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_
|