ART: Change access flag behavior in verifier
Note: this moves the miranda modifier to the upper 16 bit.
Bug: 16161620
(cherry picked from commit 7fc8f90b7160e879143be5cfd6ea3df866398884)
Change-Id: I2f591d53b7d1559171e70aaaf22225d94b4882f5
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 4474f1b..6a6286f 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2792,8 +2792,7 @@
if (kUseBakerOrBrooksReadBarrier) {
klass->AssertReadBarrierPointer();
}
- uint32_t access_flags = dex_class_def.access_flags_;
- // Make sure that none of our runtime-only flags are set.
+ uint32_t access_flags = dex_class_def.GetJavaAccessFlags();
CHECK_EQ(access_flags & ~kAccJavaFlagsMask, 0U);
klass->SetAccessFlags(access_flags);
klass->SetClassLoader(class_loader);
@@ -2936,7 +2935,7 @@
uint32_t field_idx = it.GetMemberIndex();
dst->SetDexFieldIndex(field_idx);
dst->SetDeclaringClass(klass.Get());
- dst->SetAccessFlags(it.GetMemberAccessFlags());
+ dst->SetAccessFlags(it.GetFieldAccessFlags());
}
mirror::ArtMethod* ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file,
@@ -2962,7 +2961,7 @@
dst->SetDexCacheResolvedMethods(klass->GetDexCache()->GetResolvedMethods());
dst->SetDexCacheResolvedTypes(klass->GetDexCache()->GetResolvedTypes());
- uint32_t access_flags = it.GetMemberAccessFlags();
+ uint32_t access_flags = it.GetMethodAccessFlags();
if (UNLIKELY(strcmp("finalize", method_name) == 0)) {
// Set finalizable flag on declaring class.
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 1cec264..c160253 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -201,6 +201,24 @@
uint32_t class_data_off_; // file offset to class_data_item
uint32_t static_values_off_; // file offset to EncodedArray
+ // Returns the valid access flags, that is, Java modifier bits relevant to the ClassDef type
+ // (class or interface). These are all in the lower 16b and do not contain runtime flags.
+ uint32_t GetJavaAccessFlags() const {
+ // Make sure that none of our runtime-only flags are set.
+ COMPILE_ASSERT((kAccValidClassFlags & kAccJavaFlagsMask) == kAccValidClassFlags,
+ valid_class_flags_not_subset_of_java_flags);
+ COMPILE_ASSERT((kAccValidInterfaceFlags & kAccJavaFlagsMask) == kAccValidInterfaceFlags,
+ valid_interface_flags_not_subset_of_java_flags);
+
+ if ((access_flags_ & kAccInterface) != 0) {
+ // Interface.
+ return access_flags_ & kAccValidInterfaceFlags;
+ } else {
+ // Class.
+ return access_flags_ & kAccValidClassFlags;
+ }
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(ClassDef);
};
@@ -1112,7 +1130,7 @@
return last_idx_ + method_.method_idx_delta_;
}
}
- uint32_t GetMemberAccessFlags() const {
+ uint32_t GetRawMemberAccessFlags() const {
if (pos_ < EndOfInstanceFieldsPos()) {
return field_.access_flags_;
} else {
@@ -1120,18 +1138,30 @@
return method_.access_flags_;
}
}
+ uint32_t GetFieldAccessFlags() const {
+ return GetRawMemberAccessFlags() & kAccValidFieldFlags;
+ }
+ uint32_t GetMethodAccessFlags() const {
+ return GetRawMemberAccessFlags() & kAccValidMethodFlags;
+ }
+ bool MemberIsNative() const {
+ return GetRawMemberAccessFlags() & kAccNative;
+ }
+ bool MemberIsFinal() const {
+ return GetRawMemberAccessFlags() & kAccFinal;
+ }
InvokeType GetMethodInvokeType(const DexFile::ClassDef& class_def) const {
if (HasNextDirectMethod()) {
- if ((GetMemberAccessFlags() & kAccStatic) != 0) {
+ if ((GetRawMemberAccessFlags() & kAccStatic) != 0) {
return kStatic;
} else {
return kDirect;
}
} else {
- DCHECK_EQ(GetMemberAccessFlags() & kAccStatic, 0U);
+ DCHECK_EQ(GetRawMemberAccessFlags() & kAccStatic, 0U);
if ((class_def.access_flags_ & kAccInterface) != 0) {
return kInterface;
- } else if ((GetMemberAccessFlags() & kAccConstructor) != 0) {
+ } else if ((GetRawMemberAccessFlags() & kAccConstructor) != 0) {
return kSuper;
} else {
return kVirtual;
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index 976cac9..9eba92f 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -456,9 +456,7 @@
return false;
}
- uint32_t access_field_mask = kAccPublic | kAccPrivate | kAccProtected | kAccStatic |
- kAccFinal | kAccVolatile | kAccTransient | kAccSynthetic | kAccEnum;
- if (UNLIKELY((access_flags & ~access_field_mask) != 0)) {
+ if (UNLIKELY((access_flags & ~kAccJavaFlagsMask) != 0)) {
ErrorStringPrintf("Bad class_data_item field access_flags %x", access_flags);
return false;
}
@@ -482,9 +480,8 @@
return false;
}
- uint32_t access_method_mask = kAccPublic | kAccPrivate | kAccProtected | kAccStatic |
- kAccFinal | kAccSynchronized | kAccBridge | kAccVarargs | kAccNative | kAccAbstract |
- kAccStrict | kAccSynthetic | kAccConstructor | kAccDeclaredSynchronized;
+ constexpr uint32_t access_method_mask = kAccJavaFlagsMask | kAccConstructor |
+ kAccDeclaredSynchronized;
if (UNLIKELY(((access_flags & ~access_method_mask) != 0) ||
(is_synchronized && !allow_synchronized))) {
ErrorStringPrintf("Bad class_data_item method access_flags %x", access_flags);
@@ -686,24 +683,26 @@
bool DexFileVerifier::CheckIntraClassDataItem() {
ClassDataItemIterator it(*dex_file_, ptr_);
+ // These calls use the raw access flags to check whether the whole dex field is valid.
+
for (; it.HasNextStaticField(); it.Next()) {
- if (!CheckClassDataItemField(it.GetMemberIndex(), it.GetMemberAccessFlags(), true)) {
+ if (!CheckClassDataItemField(it.GetMemberIndex(), it.GetRawMemberAccessFlags(), true)) {
return false;
}
}
for (; it.HasNextInstanceField(); it.Next()) {
- if (!CheckClassDataItemField(it.GetMemberIndex(), it.GetMemberAccessFlags(), false)) {
+ if (!CheckClassDataItemField(it.GetMemberIndex(), it.GetRawMemberAccessFlags(), false)) {
return false;
}
}
for (; it.HasNextDirectMethod(); it.Next()) {
- if (!CheckClassDataItemMethod(it.GetMemberIndex(), it.GetMemberAccessFlags(),
+ if (!CheckClassDataItemMethod(it.GetMemberIndex(), it.GetRawMemberAccessFlags(),
it.GetMethodCodeItemOffset(), true)) {
return false;
}
}
for (; it.HasNextVirtualMethod(); it.Next()) {
- if (!CheckClassDataItemMethod(it.GetMemberIndex(), it.GetMemberAccessFlags(),
+ if (!CheckClassDataItemMethod(it.GetMemberIndex(), it.GetRawMemberAccessFlags(),
it.GetMethodCodeItemOffset(), false)) {
return false;
}
diff --git a/runtime/image.cc b/runtime/image.cc
index 93ec27d..478b486 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -24,7 +24,7 @@
namespace art {
const byte ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const byte ImageHeader::kImageVersion[] = { '0', '0', '8', '\0' };
+const byte ImageHeader::kImageVersion[] = { '0', '0', '9', '\0' };
ImageHeader::ImageHeader(uint32_t image_begin,
uint32_t image_size,
diff --git a/runtime/modifiers.h b/runtime/modifiers.h
index 2814ed8..23c18f8 100644
--- a/runtime/modifiers.h
+++ b/runtime/modifiers.h
@@ -19,48 +19,77 @@
#include <stdint.h>
-static const uint32_t kAccPublic = 0x0001; // class, field, method, ic
-static const uint32_t kAccPrivate = 0x0002; // field, method, ic
-static const uint32_t kAccProtected = 0x0004; // field, method, ic
-static const uint32_t kAccStatic = 0x0008; // field, method, ic
-static const uint32_t kAccFinal = 0x0010; // class, field, method, ic
-static const uint32_t kAccSynchronized = 0x0020; // method (only allowed on natives)
-static const uint32_t kAccSuper = 0x0020; // class (not used in dex)
-static const uint32_t kAccVolatile = 0x0040; // field
-static const uint32_t kAccBridge = 0x0040; // method (1.5)
-static const uint32_t kAccTransient = 0x0080; // field
-static const uint32_t kAccVarargs = 0x0080; // method (1.5)
-static const uint32_t kAccNative = 0x0100; // method
-static const uint32_t kAccInterface = 0x0200; // class, ic
-static const uint32_t kAccAbstract = 0x0400; // class, method, ic
-static const uint32_t kAccStrict = 0x0800; // method
-static const uint32_t kAccSynthetic = 0x1000; // class, field, method, ic
-static const uint32_t kAccAnnotation = 0x2000; // class, ic (1.5)
-static const uint32_t kAccEnum = 0x4000; // class, field, ic (1.5)
+static constexpr uint32_t kAccPublic = 0x0001; // class, field, method, ic
+static constexpr uint32_t kAccPrivate = 0x0002; // field, method, ic
+static constexpr uint32_t kAccProtected = 0x0004; // field, method, ic
+static constexpr uint32_t kAccStatic = 0x0008; // field, method, ic
+static constexpr uint32_t kAccFinal = 0x0010; // class, field, method, ic
+static constexpr uint32_t kAccSynchronized = 0x0020; // method (only allowed on natives)
+static constexpr uint32_t kAccSuper = 0x0020; // class (not used in dex)
+static constexpr uint32_t kAccVolatile = 0x0040; // field
+static constexpr uint32_t kAccBridge = 0x0040; // method (1.5)
+static constexpr uint32_t kAccTransient = 0x0080; // field
+static constexpr uint32_t kAccVarargs = 0x0080; // method (1.5)
+static constexpr uint32_t kAccNative = 0x0100; // method
+static constexpr uint32_t kAccInterface = 0x0200; // class, ic
+static constexpr uint32_t kAccAbstract = 0x0400; // class, method, ic
+static constexpr uint32_t kAccStrict = 0x0800; // method
+static constexpr uint32_t kAccSynthetic = 0x1000; // class, field, method, ic
+static constexpr uint32_t kAccAnnotation = 0x2000; // class, ic (1.5)
+static constexpr uint32_t kAccEnum = 0x4000; // class, field, ic (1.5)
-static const uint32_t kAccMiranda = 0x8000; // method
+static constexpr uint32_t kAccJavaFlagsMask = 0xffff; // bits set from Java sources (low 16)
-static const uint32_t kAccJavaFlagsMask = 0xffff; // bits set from Java sources (low 16)
-
-static const uint32_t kAccConstructor = 0x00010000; // method (dex only) <init> and <clinit>
-static const uint32_t kAccDeclaredSynchronized = 0x00020000; // method (dex only)
-static const uint32_t kAccClassIsProxy = 0x00040000; // class (dex only)
-static const uint32_t kAccPreverified = 0x00080000; // class (runtime), method (dex only)
-static const uint32_t kAccFastNative = 0x0080000; // method (dex only)
-static const uint32_t kAccPortableCompiled = 0x0100000; // method (dex only)
+static constexpr uint32_t kAccConstructor = 0x00010000; // method (dex only) <(cl)init>
+static constexpr uint32_t kAccDeclaredSynchronized = 0x00020000; // method (dex only)
+static constexpr uint32_t kAccClassIsProxy = 0x00040000; // class (dex only)
+static constexpr uint32_t kAccPreverified = 0x00080000; // class (runtime),
+ // method (dex only)
+static constexpr uint32_t kAccFastNative = 0x00080000; // method (dex only)
+static constexpr uint32_t kAccPortableCompiled = 0x00100000; // method (dex only)
+static constexpr uint32_t kAccMiranda = 0x00200000; // method (dex only)
// Special runtime-only flags.
// Note: if only kAccClassIsReference is set, we have a soft reference.
-static const uint32_t kAccClassIsFinalizable = 0x80000000; // class/ancestor overrides finalize()
-static const uint32_t kAccClassIsReference = 0x08000000; // class is a soft/weak/phantom ref
-static const uint32_t kAccClassIsWeakReference = 0x04000000; // class is a weak reference
-static const uint32_t kAccClassIsFinalizerReference = 0x02000000; // class is a finalizer reference
-static const uint32_t kAccClassIsPhantomReference = 0x01000000; // class is a phantom reference
-static const uint32_t kAccReferenceFlagsMask = (kAccClassIsReference
- | kAccClassIsWeakReference
- | kAccClassIsFinalizerReference
- | kAccClassIsPhantomReference);
+// class/ancestor overrides finalize()
+static constexpr uint32_t kAccClassIsFinalizable = 0x80000000;
+// class is a soft/weak/phantom ref
+static constexpr uint32_t kAccClassIsReference = 0x08000000;
+// class is a weak reference
+static constexpr uint32_t kAccClassIsWeakReference = 0x04000000;
+// class is a finalizer reference
+static constexpr uint32_t kAccClassIsFinalizerReference = 0x02000000;
+// class is a phantom reference
+static constexpr uint32_t kAccClassIsPhantomReference = 0x01000000;
+
+static constexpr uint32_t kAccReferenceFlagsMask = (kAccClassIsReference
+ | kAccClassIsWeakReference
+ | kAccClassIsFinalizerReference
+ | kAccClassIsPhantomReference);
+
+// Valid (meaningful) bits for a field.
+static constexpr uint32_t kAccValidFieldFlags = kAccPublic | kAccPrivate | kAccProtected |
+ kAccStatic | kAccFinal | kAccVolatile | kAccTransient | kAccSynthetic | kAccEnum;
+
+// Valid (meaningful) bits for a method.
+static constexpr uint32_t kAccValidMethodFlags = kAccPublic | kAccPrivate | kAccProtected |
+ kAccStatic | kAccFinal | kAccSynchronized | kAccBridge | kAccVarargs | kAccNative |
+ kAccAbstract | kAccStrict | kAccSynthetic | kAccMiranda | kAccConstructor |
+ kAccDeclaredSynchronized;
+
+// Valid (meaningful) bits for a class (not interface).
+// Note 1. These are positive bits. Other bits may have to be zero.
+// Note 2. Inner classes can expose more access flags to Java programs. That is handled by libcore.
+static constexpr uint32_t kAccValidClassFlags = kAccPublic | kAccFinal | kAccSuper |
+ kAccAbstract | kAccSynthetic | kAccEnum;
+
+// Valid (meaningful) bits for an interface.
+// Note 1. Annotations are interfaces.
+// Note 2. These are positive bits. Other bits may have to be zero.
+// Note 3. Inner classes can expose more access flags to Java programs. That is handled by libcore.
+static constexpr uint32_t kAccValidInterfaceFlags = kAccPublic | kAccInterface |
+ kAccAbstract | kAccSynthetic | kAccAnnotation;
#endif // ART_RUNTIME_MODIFIERS_H_
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index b799588..0de1e76 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -175,7 +175,7 @@
class_def,
it.GetMethodCodeItem(),
h_method,
- it.GetMemberAccessFlags(),
+ it.GetMethodAccessFlags(),
allow_soft_failures,
false);
if (result != kNoFailure) {
@@ -223,7 +223,7 @@
class_def,
it.GetMethodCodeItem(),
h_method,
- it.GetMemberAccessFlags(),
+ it.GetMethodAccessFlags(),
allow_soft_failures,
false);
if (result != kNoFailure) {