diff options
Diffstat (limited to 'test')
| -rw-r--r-- | test/088-monitor-verification/expected.txt | 7 | ||||
| -rw-r--r-- | test/088-monitor-verification/smali/NotStructuredOverUnlock.smali | 21 | ||||
| -rw-r--r-- | test/088-monitor-verification/smali/NotStructuredUnderUnlock.smali | 21 | ||||
| -rw-r--r-- | test/088-monitor-verification/smali/OK.smali | 68 | ||||
| -rw-r--r-- | test/088-monitor-verification/smali/TooDeep.smali | 82 | ||||
| -rw-r--r-- | test/088-monitor-verification/smali/UnbalancedJoin.smali | 31 | ||||
| -rw-r--r-- | test/088-monitor-verification/smali/UnbalancedStraight.smali | 18 | ||||
| -rw-r--r-- | test/088-monitor-verification/src/Main.java | 69 | ||||
| -rw-r--r-- | test/088-monitor-verification/src/TooDeep.java | 64 | ||||
| -rw-r--r-- | test/088-monitor-verification/stack_inspect.cc | 81 | ||||
| -rw-r--r-- | test/Android.libarttest.mk | 1 |
11 files changed, 393 insertions, 70 deletions
diff --git a/test/088-monitor-verification/expected.txt b/test/088-monitor-verification/expected.txt index 07f5b0be82..13b8c73970 100644 --- a/test/088-monitor-verification/expected.txt +++ b/test/088-monitor-verification/expected.txt @@ -1,7 +1,12 @@ recursiveSync ok nestedMayThrow ok constantLock ok -excessiveNesting ok notNested ok twoPath ok triplet ok +OK +TooDeep +NotStructuredOverUnlock +NotStructuredUnderUnlock +UnbalancedJoin +UnbalancedStraight diff --git a/test/088-monitor-verification/smali/NotStructuredOverUnlock.smali b/test/088-monitor-verification/smali/NotStructuredOverUnlock.smali new file mode 100644 index 0000000000..aa0c2d5a13 --- /dev/null +++ b/test/088-monitor-verification/smali/NotStructuredOverUnlock.smali @@ -0,0 +1,21 @@ +.class public LNotStructuredOverUnlock; + +.super Ljava/lang/Object; + +.method public static run(Ljava/lang/Object;)V + .registers 3 + + invoke-static {}, LMain;->assertCallerIsInterpreted()V + + # Lock twice, but unlock thrice. + + monitor-enter v2 # 1 + monitor-enter v2 # 2 + + monitor-exit v2 # 1 + monitor-exit v2 # 2 + monitor-exit v2 # 3 + + return-void + +.end method diff --git a/test/088-monitor-verification/smali/NotStructuredUnderUnlock.smali b/test/088-monitor-verification/smali/NotStructuredUnderUnlock.smali new file mode 100644 index 0000000000..2c31fdaa85 --- /dev/null +++ b/test/088-monitor-verification/smali/NotStructuredUnderUnlock.smali @@ -0,0 +1,21 @@ +.class public LNotStructuredUnderUnlock; + +.super Ljava/lang/Object; + +.method public static run(Ljava/lang/Object;)V + .registers 3 + + invoke-static {}, LMain;->assertCallerIsInterpreted()V + + # Lock thrice, but only unlock twice. + + monitor-enter v2 # 1 + monitor-enter v2 # 2 + monitor-enter v2 # 3 + + monitor-exit v2 # 1 + monitor-exit v2 # 2 + + return-void + +.end method diff --git a/test/088-monitor-verification/smali/OK.smali b/test/088-monitor-verification/smali/OK.smali new file mode 100644 index 0000000000..596798d80c --- /dev/null +++ b/test/088-monitor-verification/smali/OK.smali @@ -0,0 +1,68 @@ +.class public LOK; + +.super Ljava/lang/Object; + +.method public static run(Ljava/lang/Object;Ljava/lang/Object;)V + .registers 3 + + invoke-static {v1, v2}, LOK;->runNoMonitors(Ljava/lang/Object;Ljava/lang/Object;)V + + invoke-static {v1, v2}, LOK;->runStraightLine(Ljava/lang/Object;Ljava/lang/Object;)V + + invoke-static {v1, v2}, LOK;->runBalancedJoin(Ljava/lang/Object;Ljava/lang/Object;)V + + return-void + +.end method + + + +.method public static runNoMonitors(Ljava/lang/Object;Ljava/lang/Object;)V + .registers 3 + + invoke-static {}, LMain;->assertCallerIsManaged()V + + return-void + +.end method + +.method public static runStraightLine(Ljava/lang/Object;Ljava/lang/Object;)V + .registers 3 + + invoke-static {}, LMain;->assertCallerIsManaged()V + + monitor-enter v1 # 1 + monitor-enter v2 # 2 + + monitor-exit v2 # 2 + monitor-exit v1 # 1 + + return-void + +.end method + +.method public static runBalancedJoin(Ljava/lang/Object;Ljava/lang/Object;)V + .registers 3 + + invoke-static {}, LMain;->assertCallerIsManaged()V + + monitor-enter v1 # 1 + + if-eqz v2, :Lnull + +:LnotNull + + monitor-enter v2 # 2 + goto :Lend + +:Lnull + monitor-enter v2 # 2 + +:Lend + + monitor-exit v2 # 2 + monitor-exit v1 # 1 + + return-void + +.end method diff --git a/test/088-monitor-verification/smali/TooDeep.smali b/test/088-monitor-verification/smali/TooDeep.smali new file mode 100644 index 0000000000..1a8f2f06e8 --- /dev/null +++ b/test/088-monitor-verification/smali/TooDeep.smali @@ -0,0 +1,82 @@ +.class public LTooDeep; + +.super Ljava/lang/Object; + +.method public static run(Ljava/lang/Object;)V + .registers 3 + + # Lock depth is 33, which is more than the verifier supports. This should have been punted to + # the interpreter. + invoke-static {}, LMain;->assertCallerIsInterpreted()V + + monitor-enter v2 # 1 + monitor-enter v2 # 2 + monitor-enter v2 # 3 + monitor-enter v2 # 4 + monitor-enter v2 # 5 + monitor-enter v2 # 6 + monitor-enter v2 # 7 + monitor-enter v2 # 8 + monitor-enter v2 # 9 + monitor-enter v2 # 10 + monitor-enter v2 # 11 + monitor-enter v2 # 12 + monitor-enter v2 # 13 + monitor-enter v2 # 14 + monitor-enter v2 # 15 + monitor-enter v2 # 16 + monitor-enter v2 # 17 + monitor-enter v2 # 18 + monitor-enter v2 # 19 + monitor-enter v2 # 20 + monitor-enter v2 # 21 + monitor-enter v2 # 22 + monitor-enter v2 # 23 + monitor-enter v2 # 24 + monitor-enter v2 # 25 + monitor-enter v2 # 26 + monitor-enter v2 # 27 + monitor-enter v2 # 28 + monitor-enter v2 # 29 + monitor-enter v2 # 30 + monitor-enter v2 # 31 + monitor-enter v2 # 32 + monitor-enter v2 # 33 + + monitor-exit v2 # 1 + monitor-exit v2 # 2 + monitor-exit v2 # 3 + monitor-exit v2 # 4 + monitor-exit v2 # 5 + monitor-exit v2 # 6 + monitor-exit v2 # 7 + monitor-exit v2 # 8 + monitor-exit v2 # 9 + monitor-exit v2 # 10 + monitor-exit v2 # 11 + monitor-exit v2 # 12 + monitor-exit v2 # 13 + monitor-exit v2 # 14 + monitor-exit v2 # 15 + monitor-exit v2 # 16 + monitor-exit v2 # 17 + monitor-exit v2 # 18 + monitor-exit v2 # 19 + monitor-exit v2 # 20 + monitor-exit v2 # 21 + monitor-exit v2 # 22 + monitor-exit v2 # 23 + monitor-exit v2 # 24 + monitor-exit v2 # 25 + monitor-exit v2 # 26 + monitor-exit v2 # 27 + monitor-exit v2 # 28 + monitor-exit v2 # 29 + monitor-exit v2 # 30 + monitor-exit v2 # 31 + monitor-exit v2 # 32 + monitor-exit v2 # 33 + + return-void + +.end method diff --git a/test/088-monitor-verification/smali/UnbalancedJoin.smali b/test/088-monitor-verification/smali/UnbalancedJoin.smali new file mode 100644 index 0000000000..da8f7732af --- /dev/null +++ b/test/088-monitor-verification/smali/UnbalancedJoin.smali @@ -0,0 +1,31 @@ +.class public LUnbalancedJoin; + +.super Ljava/lang/Object; + +.method public static run(Ljava/lang/Object;Ljava/lang/Object;)V + .registers 3 + + invoke-static {}, LMain;->assertCallerIsInterpreted()V + + if-eqz v2, :Lnull + +:LnotNull + + monitor-enter v1 # 1 + monitor-enter v2 # 2 + goto :Lend + +:Lnull + monitor-enter v2 # 1 + monitor-enter v1 # 2 + +:Lend + + # Lock levels are "opposite" for the joined flows. + + monitor-exit v2 # 2 + monitor-exit v1 # 1 + + return-void + +.end method diff --git a/test/088-monitor-verification/smali/UnbalancedStraight.smali b/test/088-monitor-verification/smali/UnbalancedStraight.smali new file mode 100644 index 0000000000..68edb6c783 --- /dev/null +++ b/test/088-monitor-verification/smali/UnbalancedStraight.smali @@ -0,0 +1,18 @@ +.class public LUnbalancedStraight; + +.super Ljava/lang/Object; + +.method public static run(Ljava/lang/Object;Ljava/lang/Object;)V + .registers 3 + + invoke-static {}, LMain;->assertCallerIsInterpreted()V + + monitor-enter v1 # 1 + monitor-enter v2 # 2 + + monitor-exit v1 # 1 Unbalanced unlock. + monitor-exit v2 # 2 + + return-void + +.end method diff --git a/test/088-monitor-verification/src/Main.java b/test/088-monitor-verification/src/Main.java index b60c71e668..af1eaea308 100644 --- a/test/088-monitor-verification/src/Main.java +++ b/test/088-monitor-verification/src/Main.java @@ -14,6 +14,9 @@ * limitations under the License. */ +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; /* * Entry point and tests that are expected to succeed. @@ -38,11 +41,6 @@ public class Main { System.out.println("constantLock ok"); m.notExcessiveNesting(); - try { - TooDeep.excessiveNesting(); - System.err.println("excessiveNesting did not throw"); - } catch (VerifyError ve) {} - System.out.println("excessiveNesting ok"); m.notNested(); System.out.println("notNested ok"); @@ -55,6 +53,9 @@ public class Main { m.triplet(obj1, obj2, 0); System.out.println("triplet ok"); + + System.loadLibrary("arttest"); + runSmaliTests(); } /** @@ -216,4 +217,62 @@ public class Main { doNothing(localObj); } + + // Smali testing code. + private static void runSmaliTests() { + runTest("OK", new Object[] { new Object(), new Object() }, null); + runTest("TooDeep", new Object[] { new Object() }, null); + runTest("NotStructuredOverUnlock", new Object[] { new Object() }, + IllegalMonitorStateException.class); + runTest("NotStructuredUnderUnlock", new Object[] { new Object() }, null); + // TODO: new IllegalMonitorStateException()); + runTest("UnbalancedJoin", new Object[] { new Object(), new Object() }, null); + runTest("UnbalancedStraight", new Object[] { new Object(), new Object() }, null); + } + + private static void runTest(String className, Object[] parameters, Class<?> excType) { + System.out.println(className); + try { + Class<?> c = Class.forName(className); + + Method[] methods = c.getDeclaredMethods(); + + // For simplicity we assume that test methods are not overloaded. So searching by name + // will give us the method we need to run. + Method method = null; + for (Method m : methods) { + if (m.getName().equals("run")) { + method = m; + break; + } + } + + if (method == null) { + System.out.println("Could not find test method for " + className); + } else if (!Modifier.isStatic(method.getModifiers())) { + System.out.println("Test method for " + className + " is not static."); + } else { + method.invoke(null, parameters); + if (excType != null) { + System.out.println("Expected an exception in " + className); + } + } + } catch (Throwable exc) { + if (excType == null) { + System.out.println("Did not expect exception " + exc + " for " + className); + exc.printStackTrace(System.out); + } else if (exc instanceof InvocationTargetException && exc.getCause() != null && + exc.getCause().getClass().equals(excType)) { + // Expected exception is wrapped in InvocationTargetException. + } else if (!excType.equals(exc.getClass())) { + System.out.println("Expected " + excType.getName() + ", but got " + exc.getClass()); + } else { + // Expected exception, do nothing. + } + } + } + + // Helpers for the smali code. + public static native void assertCallerIsInterpreted(); + public static native void assertCallerIsManaged(); } diff --git a/test/088-monitor-verification/src/TooDeep.java b/test/088-monitor-verification/src/TooDeep.java deleted file mode 100644 index 76192e55c6..0000000000 --- a/test/088-monitor-verification/src/TooDeep.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - - -/** - * The class has a method with too many levels of nested "synchronized" - * blocks. The verifier will reject it. - * - * (It would be perfectly okay if the verifier *didn't* reject this. - * The goal here is just to exercise the failure path. It also serves - * as a check to see if the monitor checks are enabled.) - */ -public class TooDeep { - - public static void excessiveNesting() { - synchronized (TooDeep.class) { // 1 - synchronized (TooDeep.class) { // 2 - synchronized (TooDeep.class) { // 3 - synchronized (TooDeep.class) { // 4 - synchronized (TooDeep.class) { // 5 - synchronized (TooDeep.class) { // 6 - synchronized (TooDeep.class) { // 7 - synchronized (TooDeep.class) { // 8 - synchronized (TooDeep.class) { // 9 - synchronized (TooDeep.class) { // 10 - synchronized (TooDeep.class) { // 11 - synchronized (TooDeep.class) { // 12 - synchronized (TooDeep.class) { // 13 - synchronized (TooDeep.class) { // 14 - synchronized (TooDeep.class) { // 15 - synchronized (TooDeep.class) { // 16 - synchronized (TooDeep.class) { // 17 - synchronized (TooDeep.class) { // 18 - synchronized (TooDeep.class) { // 19 - synchronized (TooDeep.class) { // 20 - synchronized (TooDeep.class) { // 21 - synchronized (TooDeep.class) { // 22 - synchronized (TooDeep.class) { // 23 - synchronized (TooDeep.class) { // 24 - synchronized (TooDeep.class) { // 25 - synchronized (TooDeep.class) { // 26 - synchronized (TooDeep.class) { // 27 - synchronized (TooDeep.class) { // 28 - synchronized (TooDeep.class) { // 29 - synchronized (TooDeep.class) { // 30 - synchronized (TooDeep.class) { // 31 - synchronized (TooDeep.class) { // 32 - synchronized (TooDeep.class) { // 33 - }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} - } -} diff --git a/test/088-monitor-verification/stack_inspect.cc b/test/088-monitor-verification/stack_inspect.cc new file mode 100644 index 0000000000..e2899c3d68 --- /dev/null +++ b/test/088-monitor-verification/stack_inspect.cc @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2015 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. + */ + +#include "jni.h" + +#include "base/logging.h" +#include "dex_file-inl.h" +#include "mirror/class-inl.h" +#include "nth_caller_visitor.h" +#include "runtime.h" +#include "scoped_thread_state_change.h" +#include "stack.h" +#include "thread-inl.h" + +namespace art { + +// public static native void assertCallerIsInterpreted(); + +extern "C" JNIEXPORT void JNICALL Java_Main_assertCallerIsInterpreted(JNIEnv* env, jclass) { + LOG(INFO) << "assertCallerIsInterpreted"; + + ScopedObjectAccess soa(env); + NthCallerVisitor caller(soa.Self(), 1, false); + caller.WalkStack(); + CHECK(caller.caller != nullptr); + LOG(INFO) << PrettyMethod(caller.caller); + CHECK(caller.GetCurrentShadowFrame() != nullptr); +} + +// public static native void assertCallerIsManaged(); + +extern "C" JNIEXPORT void JNICALL Java_Main_assertCallerIsManaged(JNIEnv* env, jclass cls) { + // Note: needs some smarts to not fail if there is no managed code, at all. + LOG(INFO) << "assertCallerIsManaged"; + + ScopedObjectAccess soa(env); + + mirror::Class* klass = soa.Decode<mirror::Class*>(cls); + const DexFile& dex_file = klass->GetDexFile(); + const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); + if (oat_dex_file == nullptr) { + // No oat file, this must be a test configuration that doesn't compile at all. Ignore that the + // result will be that we're running the interpreter. + return; + } + + NthCallerVisitor caller(soa.Self(), 1, false); + caller.WalkStack(); + CHECK(caller.caller != nullptr); + LOG(INFO) << PrettyMethod(caller.caller); + + if (caller.GetCurrentShadowFrame() == nullptr) { + // Not a shadow frame, this looks good. + return; + } + + // This could be an interpret-only or a verify-at-runtime compilation, or a read-barrier variant, + // or... It's not really safe to just reject now. Let's look at the access flags. If the method + // was successfully verified, its access flags should be set to mark it preverified, except when + // we're running soft-fail tests. + if (Runtime::Current()->IsVerificationSoftFail()) { + // Soft-fail config. Everything should be running with interpreter access checks, potentially. + return; + } + CHECK(caller.caller->IsPreverified()); +} + +} // namespace art diff --git a/test/Android.libarttest.mk b/test/Android.libarttest.mk index 021e25c967..82f8c79512 100644 --- a/test/Android.libarttest.mk +++ b/test/Android.libarttest.mk @@ -25,6 +25,7 @@ LIBARTTEST_COMMON_SRC_FILES := \ 004-StackWalk/stack_walk_jni.cc \ 004-UnsafeTest/unsafe_test.cc \ 051-thread/thread_test.cc \ + 088-monitor-verification/stack_inspect.cc \ 116-nodex2oat/nodex2oat.cc \ 117-nopatchoat/nopatchoat.cc \ 118-noimage-dex2oat/noimage-dex2oat.cc \ |