summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Treehugger Robot <treehugger-gerrit@google.com> 2018-07-05 16:32:16 +0000
committer Gerrit Code Review <noreply-gerritcodereview@google.com> 2018-07-05 16:32:16 +0000
commit91b6befbb0a323ccbdce5f0631e260346e04f045 (patch)
treeceb3c5608472a396f4f090c315c5cf16386fabd1
parent4a72f8b1baec1fb93105e381edb1bad60e372540 (diff)
parent82898ed01eedfb82a5b4adfe1327b827210af3ca (diff)
Merge "Handle a special case of lock aliasing during lock verification"
-rw-r--r--runtime/verifier/method_verifier.cc39
-rw-r--r--test/800-smali/expected.txt2
-rw-r--r--test/800-smali/smali/ConstClassAliasing.smali12
-rw-r--r--test/800-smali/src/Main.java23
-rw-r--r--test/common/runtime_state.cc6
5 files changed, 80 insertions, 2 deletions
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 47877bd195..77105a8603 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -2254,6 +2254,45 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
}
break;
+ // Catch a case of register aliasing when two registers are linked to the same
+ // java.lang.Class object via two consequent const-class instructions immediately
+ // preceding monitor-enter called on one of those registers.
+ case Instruction::CONST_CLASS: {
+ // Get the second previous instruction.
+ if (prev_idx == 0 || GetInstructionFlags(prev_idx).IsBranchTarget()) {
+ break;
+ }
+ prev_idx--;
+ while (0 != prev_idx && !GetInstructionFlags(prev_idx).IsOpcode()) {
+ prev_idx--;
+ }
+ const Instruction& prev2_inst = code_item_accessor_.InstructionAt(prev_idx);
+
+ // Match the pattern "const-class; const-class; monitor-enter;"
+ if (prev2_inst.Opcode() != Instruction::CONST_CLASS) {
+ break;
+ }
+
+ // Ensure both const-classes are called for the same type_idx.
+ if (prev_inst.VRegB_21c() != prev2_inst.VRegB_21c()) {
+ break;
+ }
+
+ // Update the lock status for the aliased register.
+ if (prev_inst.VRegA() == inst->VRegA_11x()) {
+ work_line_->CopyRegister1(this,
+ prev2_inst.VRegA(),
+ inst->VRegA_11x(),
+ kTypeCategoryRef);
+ } else if (prev2_inst.VRegA() == inst->VRegA_11x()) {
+ work_line_->CopyRegister1(this,
+ prev_inst.VRegA(),
+ inst->VRegA_11x(),
+ kTypeCategoryRef);
+ }
+ break;
+ }
+
default: // Other instruction types ignored.
break;
}
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
index b8324e54e3..f3c3f03a9a 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -1,3 +1,4 @@
+JNI_OnLoad called
PackedSwitch
PackedSwitch key INT_MAX
PackedSwitch key overflow
@@ -71,4 +72,5 @@ b/29778499 (1)
b/29778499 (2)
b/30458218
b/31313170
+ConstClassAliasing
Done!
diff --git a/test/800-smali/smali/ConstClassAliasing.smali b/test/800-smali/smali/ConstClassAliasing.smali
new file mode 100644
index 0000000000..a65d9a7a5d
--- /dev/null
+++ b/test/800-smali/smali/ConstClassAliasing.smali
@@ -0,0 +1,12 @@
+.class public LConstClassAliasing;
+
+.super Ljava/lang/Object;
+
+.method public static run()V
+ .registers 2
+ const-class v0, Ljava/lang/Object;
+ const-class v1, Ljava/lang/Object;
+ monitor-enter v0
+ monitor-exit v1
+ return-void
+.end method
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index 8d39f0971f..75a02648b5 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -27,13 +27,21 @@ public class Main {
private static class TestCase {
public TestCase(String testName, String testClass, String testMethodName, Object[] values,
- Throwable expectedException, Object expectedReturn) {
+ Throwable expectedException, Object expectedReturn,
+ boolean checkCompiled) {
this.testName = testName;
this.testClass = testClass;
this.testMethodName = testMethodName;
this.values = values;
this.expectedException = expectedException;
this.expectedReturn = expectedReturn;
+ this.checkCompiled = checkCompiled;
+ }
+
+ public TestCase(String testName, String testClass, String testMethodName, Object[] values,
+ Throwable expectedException, Object expectedReturn) {
+ this(testName, testClass, testMethodName, values, expectedException,
+ expectedReturn, false);
}
String testName;
@@ -42,6 +50,7 @@ public class Main {
Object[] values;
Throwable expectedException;
Object expectedReturn;
+ boolean checkCompiled;
}
private List<TestCase> testCases;
@@ -182,6 +191,8 @@ public class Main {
new IncompatibleClassChangeError(), null));
testCases.add(new TestCase("b/30458218", "B30458218", "run", null, null, null));
testCases.add(new TestCase("b/31313170", "B31313170", "run", null, null, 0));
+ testCases.add(new TestCase("ConstClassAliasing", "ConstClassAliasing", "run", null, null,
+ null, true));
}
public void runTests() {
@@ -235,6 +246,11 @@ public class Main {
errorReturn = new IllegalStateException("Expected return " +
tc.expectedReturn +
", but got " + retValue);
+ } else if (tc.checkCompiled && compiledWithOptimizing() &&
+ !isAotCompiled(c, method.getName())) {
+ errorReturn = new IllegalStateException("Expected method " + method.getName() +
+ " of class " + c.getName() +
+ " be compiled in test " + tc.testName);
} else {
// Expected result, do nothing.
}
@@ -260,10 +276,15 @@ public class Main {
}
public static void main(String[] args) throws Exception {
+ System.loadLibrary(args[0]);
+
Main main = new Main();
main.runTests();
System.out.println("Done!");
}
+
+ private native static boolean isAotCompiled(Class<?> cls, String methodName);
+ private native static boolean compiledWithOptimizing();
}
diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc
index f2da6febe0..abbe6ecbe8 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -132,9 +132,13 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_compiledWithOptimizing(JNIEnv* e
constexpr const char* kInterpretOnly = "interpret-only";
constexpr const char* kVerifyNone = "verify-none";
constexpr const char* kVerifyAtRuntime = "verify-at-runtime";
+ constexpr const char* kQuicken = "quicken";
+ constexpr const char* kExtract = "extract";
if (strncmp(filter, kInterpretOnly, strlen(kInterpretOnly)) == 0 ||
strncmp(filter, kVerifyNone, strlen(kVerifyNone)) == 0 ||
- strncmp(filter, kVerifyAtRuntime, strlen(kVerifyAtRuntime)) == 0) {
+ strncmp(filter, kVerifyAtRuntime, strlen(kVerifyAtRuntime)) == 0 ||
+ strncmp(filter, kExtract, strlen(kExtract)) == 0 ||
+ strncmp(filter, kQuicken, strlen(kQuicken)) == 0) {
return JNI_FALSE;
}
}