ART: Monitor-stack merging should not be handled as throwing
Mismatched stacks and other issues on merging register lines should
not be handled as a pending runtime exception. Actual exceptions
will be thrown at monitor-enter/exit and return sites. Both are
already covered: the former by being annotated kThrow, the latter
by explicit checks for the stack (and end of control flow).
Thus, Fail() with pending_exc set to false in register line merging.
This still triggers lock verification at runtime.
Bug: 121245951
Test: m test-art-host
Change-Id: I06acca2920110e3de2a2bed7bae6695788f77449
diff --git a/runtime/verifier/register_line.cc b/runtime/verifier/register_line.cc
index 1bbf5a6..b69267c 100644
--- a/runtime/verifier/register_line.cc
+++ b/runtime/verifier/register_line.cc
@@ -442,7 +442,7 @@
}
if (monitors_.size() > 0 || incoming_line->monitors_.size() > 0) {
if (monitors_.size() != incoming_line->monitors_.size()) {
- verifier->Fail(VERIFY_ERROR_LOCKING);
+ verifier->Fail(VERIFY_ERROR_LOCKING, /*pending_exc=*/ false);
if (kDumpLockFailures) {
VLOG(verifier) << "mismatched stack depths (depth=" << MonitorStackDepth()
<< ", incoming depth=" << incoming_line->MonitorStackDepth() << ") in "
@@ -476,7 +476,7 @@
!FindLockAliasedRegister(idx,
incoming_line->reg_to_lock_depths_,
reg_to_lock_depths_)) {
- verifier->Fail(VERIFY_ERROR_LOCKING);
+ verifier->Fail(VERIFY_ERROR_LOCKING, /*pending_exc=*/ false);
if (kDumpLockFailures) {
VLOG(verifier) << "mismatched stack depths for register v" << idx
<< ": " << depths << " != " << incoming_depths << " in "
@@ -517,7 +517,7 @@
incoming_line->reg_to_lock_depths_,
reg_to_lock_depths_)) {
// No aliases for both current and incoming, we'll lose information.
- verifier->Fail(VERIFY_ERROR_LOCKING);
+ verifier->Fail(VERIFY_ERROR_LOCKING, /*pending_exc=*/ false);
if (kDumpLockFailures) {
VLOG(verifier) << "mismatched lock levels for register v" << idx << ": "
<< std::hex << locked_levels << std::dec << " != "
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
index 88dc054..fbf10bb 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -77,4 +77,7 @@
b/122501785
b/134061982
b/134061982 (2)
+b/121245951
+b/121245951 (2)
+b/121245951 (3)
Done!
diff --git a/test/800-smali/smali/b_121245951.smali b/test/800-smali/smali/b_121245951.smali
new file mode 100644
index 0000000..4faaf67
--- /dev/null
+++ b/test/800-smali/smali/b_121245951.smali
@@ -0,0 +1,26 @@
+.class public LB121245951;
+
+.super Ljava/lang/Object;
+
+.method public static run(ZLjava/lang/Object;)V
+ .registers 3
+
+ # Create an unequal lock stack.
+
+ if-eqz v1, :LfalseBranch
+
+:LtrueBranch
+ monitor-enter v2
+ monitor-enter v2
+ goto :Ljoin
+
+:LfalseBranch
+ monitor-enter v2
+ goto :Ljoin
+
+:Ljoin
+ monitor-exit v2
+
+ # Should throw here.
+ return-void
+.end method
diff --git a/test/800-smali/smali/b_121245951_2.smali b/test/800-smali/smali/b_121245951_2.smali
new file mode 100644
index 0000000..0750bb0
--- /dev/null
+++ b/test/800-smali/smali/b_121245951_2.smali
@@ -0,0 +1,30 @@
+.class public LB121245951_2;
+
+.super Ljava/lang/Object;
+
+.method public static run(ZLjava/lang/Object;)V
+ .registers 3
+
+ # Create an unequal lock stack.
+
+ if-eqz v1, :LfalseBranch
+
+:LtrueBranch
+ monitor-enter v2
+ monitor-enter v2
+ const/4 v0, 0x0
+ goto :Ljoin
+
+:LfalseBranch
+ monitor-enter v2
+ move-object v0, v2
+ goto :Ljoin
+
+:Ljoin
+ monitor-exit v2
+
+ # This should fail the class
+ add-int/lit8 v0, v0, 0x1
+
+ return-void
+.end method
diff --git a/test/800-smali/smali/b_121245951_3.smali b/test/800-smali/smali/b_121245951_3.smali
new file mode 100644
index 0000000..b6e7b1c
--- /dev/null
+++ b/test/800-smali/smali/b_121245951_3.smali
@@ -0,0 +1,33 @@
+.class public LB121245951_3;
+
+.super Ljava/lang/Object;
+
+.method public static run(Ljava/lang/Object;)V
+ .registers 3
+
+ const/4 v1, 0x1
+
+:LcatchStart
+
+ monitor-enter v2
+
+ # Possibly throwing to merge v1 into catch handler as int.
+ sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream;
+
+ move-object v1, v2
+
+ # This should cause a runtime failure, and not merge into the
+ # catch handler.
+ return-void
+
+:LcatchEnd
+:LcatchHandler
+ move-exception v0
+ # If the lock fail at the return-void above merged into the catch
+ # handler, this will fail the class.
+ add-int/lit8 v1, v1, 0x1
+ throw v0
+
+.catchall {:LcatchStart .. :LcatchEnd} :LcatchHandler
+
+.end method
\ No newline at end of file
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index ce7426f..90476b3 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -201,6 +201,12 @@
new NullPointerException(), 0));
testCases.add(new TestCase("b/134061982 (2)", "B134061982_2", "run", new Object[] { 0 },
new VerifyError(), 0));
+ testCases.add(new TestCase("b/121245951", "B121245951", "run", new Object[] { true,
+ new Object() }, new IllegalMonitorStateException(), 0));
+ testCases.add(new TestCase("b/121245951 (2)", "B121245951_2", "run", new Object[] { true,
+ new Object() }, new VerifyError(), 0));
+ testCases.add(new TestCase("b/121245951 (3)", "B121245951_3", "run", new Object[] {
+ new Object() }, new IllegalMonitorStateException(), 0));
}
public void runTests() {