diff options
| author | 2018-07-05 16:32:16 +0000 | |
|---|---|---|
| committer | 2018-07-05 16:32:16 +0000 | |
| commit | 91b6befbb0a323ccbdce5f0631e260346e04f045 (patch) | |
| tree | ceb3c5608472a396f4f090c315c5cf16386fabd1 | |
| parent | 4a72f8b1baec1fb93105e381edb1bad60e372540 (diff) | |
| parent | 82898ed01eedfb82a5b4adfe1327b827210af3ca (diff) | |
Merge "Handle a special case of lock aliasing during lock verification"
| -rw-r--r-- | runtime/verifier/method_verifier.cc | 39 | ||||
| -rw-r--r-- | test/800-smali/expected.txt | 2 | ||||
| -rw-r--r-- | test/800-smali/smali/ConstClassAliasing.smali | 12 | ||||
| -rw-r--r-- | test/800-smali/src/Main.java | 23 | ||||
| -rw-r--r-- | test/common/runtime_state.cc | 6 |
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; } } |