Fix minor problems with interface verification and default methods.
Previously we would fail verification on some <clinit> methods when
default methods are enabled and they are not marked as public.
Previously we would also give verifier soft failures when using
interface statics.
Bug: 24618811
Change-Id: I735740b4058bfd71e67bc3fb99e6a8c0c4696b01
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index e1d4160..2db79ab 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -665,20 +665,22 @@
// Interfaces may always have static initializers for their fields. If we are running with
// default methods enabled we also allow other public, static, non-final methods to have code.
// Otherwise that is the only type of method allowed.
- if (runtime->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods)) {
- if (IsInstanceConstructor()) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have non-static constructor";
- return false;
- } else if (method_access_flags_ & kAccFinal) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have final methods";
- return false;
- } else if (!(method_access_flags_ & kAccPublic)) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have non-public members";
+ if (!(IsConstructor() && IsStatic())) {
+ if (runtime->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods)) {
+ if (IsInstanceConstructor()) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have non-static constructor";
+ return false;
+ } else if (method_access_flags_ & kAccFinal) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have final methods";
+ return false;
+ } else if (!(method_access_flags_ & kAccPublic)) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have non-public members";
+ return false;
+ }
+ } else {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interface methods must be abstract";
return false;
}
- } else if (!IsConstructor() || !IsStatic()) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interface methods must be abstract";
- return false;
}
}
@@ -3662,8 +3664,15 @@
<< PrettyMethod(res_method);
return nullptr;
}
- // Check that interface methods match interface classes.
- if (klass->IsInterface() && method_type != METHOD_INTERFACE) {
+ // Check that interface methods are static or match interface classes.
+ // We only allow statics if we don't have default methods enabled.
+ Runtime* runtime = Runtime::Current();
+ const bool default_methods_supported =
+ runtime == nullptr ||
+ runtime->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods);
+ if (klass->IsInterface() &&
+ method_type != METHOD_INTERFACE &&
+ (!default_methods_supported || method_type != METHOD_STATIC)) {
Fail(VERIFY_ERROR_CLASS_CHANGE) << "non-interface method " << PrettyMethod(res_method)
<< " is in an interface class " << PrettyClass(klass);
return nullptr;
diff --git a/test/962-iface-static/smali/Displayer.smali b/test/962-iface-static/smali/Displayer.smali
index 06bec16..ed4c013 100644
--- a/test/962-iface-static/smali/Displayer.smali
+++ b/test/962-iface-static/smali/Displayer.smali
@@ -27,7 +27,7 @@
.class public LDisplayer;
.super Ljava/lang/Object;
-.method public static <clinit>()V
+.method static constructor <clinit>()V
.locals 3
sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
const-string v0, "init"
diff --git a/test/962-iface-static/smali/iface.smali b/test/962-iface-static/smali/iface.smali
index 441aae6..5b9c03e 100644
--- a/test/962-iface-static/smali/iface.smali
+++ b/test/962-iface-static/smali/iface.smali
@@ -27,7 +27,7 @@
.field public final static f:LDisplayer;
-.method public static <clinit>()V
+.method static constructor <clinit>()V
.locals 3
new-instance v1, LDisplayer;
invoke-direct {v1}, LDisplayer;-><init>()V
diff --git a/test/964-default-iface-init-generated/util-src/generate_smali.py b/test/964-default-iface-init-generated/util-src/generate_smali.py
index be2d3ba..3c138ab 100755
--- a/test/964-default-iface-init-generated/util-src/generate_smali.py
+++ b/test/964-default-iface-init-generated/util-src/generate_smali.py
@@ -334,7 +334,7 @@
# public static final Displayer field = new Displayer("{tree}");
.field public final static field:LDisplayer;
-.method public static constructor <clinit>()V
+.method static constructor <clinit>()V
.locals 3
const-string v2, "{tree}"
new-instance v1, LDisplayer;