OSDN Git Service

Don't verify runtime only opcodes in the data-flow phase of verification.
authorIan Rogers <irogers@google.com>
Fri, 13 Jun 2014 17:31:28 +0000 (10:31 -0700)
committerIan Rogers <irogers@google.com>
Fri, 13 Jun 2014 18:25:17 +0000 (11:25 -0700)
Bug: 15570344
Change-Id: I0304e8742a1d0318783ba72862e684ab91f63d0e

runtime/dex_instruction.h
runtime/dex_instruction_list.h
runtime/verifier/method_verifier.cc

index 1ff5c19..edba502 100644 (file)
@@ -145,27 +145,28 @@ class Instruction {
   };
 
   enum VerifyFlag {
-    kVerifyNone            = 0x00000,
-    kVerifyRegA            = 0x00001,
-    kVerifyRegAWide        = 0x00002,
-    kVerifyRegB            = 0x00004,
-    kVerifyRegBField       = 0x00008,
-    kVerifyRegBMethod      = 0x00010,
-    kVerifyRegBNewInstance = 0x00020,
-    kVerifyRegBString      = 0x00040,
-    kVerifyRegBType        = 0x00080,
-    kVerifyRegBWide        = 0x00100,
-    kVerifyRegC            = 0x00200,
-    kVerifyRegCField       = 0x00400,
-    kVerifyRegCNewArray    = 0x00800,
-    kVerifyRegCType        = 0x01000,
-    kVerifyRegCWide        = 0x02000,
-    kVerifyArrayData       = 0x04000,
-    kVerifyBranchTarget    = 0x08000,
-    kVerifySwitchTargets   = 0x10000,
-    kVerifyVarArg          = 0x20000,
-    kVerifyVarArgRange     = 0x40000,
-    kVerifyError           = 0x80000,
+    kVerifyNone            = 0x000000,
+    kVerifyRegA            = 0x000001,
+    kVerifyRegAWide        = 0x000002,
+    kVerifyRegB            = 0x000004,
+    kVerifyRegBField       = 0x000008,
+    kVerifyRegBMethod      = 0x000010,
+    kVerifyRegBNewInstance = 0x000020,
+    kVerifyRegBString      = 0x000040,
+    kVerifyRegBType        = 0x000080,
+    kVerifyRegBWide        = 0x000100,
+    kVerifyRegC            = 0x000200,
+    kVerifyRegCField       = 0x000400,
+    kVerifyRegCNewArray    = 0x000800,
+    kVerifyRegCType        = 0x001000,
+    kVerifyRegCWide        = 0x002000,
+    kVerifyArrayData       = 0x004000,
+    kVerifyBranchTarget    = 0x008000,
+    kVerifySwitchTargets   = 0x010000,
+    kVerifyVarArg          = 0x020000,
+    kVerifyVarArgRange     = 0x040000,
+    kVerifyRuntimeOnly     = 0x080000,
+    kVerifyError           = 0x100000,
   };
 
   static constexpr uint32_t kMaxVarArgRegs = 5;
@@ -493,18 +494,23 @@ class Instruction {
   }
 
   int GetVerifyTypeArgumentB() const {
-    return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegB | kVerifyRegBField | kVerifyRegBMethod |
-             kVerifyRegBNewInstance | kVerifyRegBString | kVerifyRegBType | kVerifyRegBWide));
+    return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegB | kVerifyRegBField |
+        kVerifyRegBMethod | kVerifyRegBNewInstance | kVerifyRegBString | kVerifyRegBType |
+        kVerifyRegBWide));
   }
 
   int GetVerifyTypeArgumentC() const {
     return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegC | kVerifyRegCField |
-             kVerifyRegCNewArray | kVerifyRegCType | kVerifyRegCWide));
+        kVerifyRegCNewArray | kVerifyRegCType | kVerifyRegCWide));
   }
 
   int GetVerifyExtraFlags() const {
     return (kInstructionVerifyFlags[Opcode()] & (kVerifyArrayData | kVerifyBranchTarget |
-             kVerifySwitchTargets | kVerifyVarArg | kVerifyVarArgRange | kVerifyError));
+        kVerifySwitchTargets | kVerifyVarArg | kVerifyVarArgRange | kVerifyError));
+  }
+
+  bool GetVerifyIsRuntimeOnly() const {
+    return (kInstructionVerifyFlags[Opcode()] & kVerifyRuntimeOnly) != 0;
   }
 
   // Get the dex PC of this instruction as a offset in code units from the beginning of insns.
index f43e42f..4cda58b 100644 (file)
   V(0xE0, SHL_INT_LIT8, "shl-int/lit8", k22b, true, kNone, kContinue | kShl | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
   V(0xE1, SHR_INT_LIT8, "shr-int/lit8", k22b, true, kNone, kContinue | kShr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
   V(0xE2, USHR_INT_LIT8, "ushr-int/lit8", k22b, true, kNone, kContinue | kUshr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xE3, IGET_QUICK, "iget-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xE4, IGET_WIDE_QUICK, "iget-wide-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB) \
-  V(0xE5, IGET_OBJECT_QUICK, "iget-object-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xE6, IPUT_QUICK, "iput-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xE7, IPUT_WIDE_QUICK, "iput-wide-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB) \
-  V(0xE8, IPUT_OBJECT_QUICK, "iput-object-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xE9, INVOKE_VIRTUAL_QUICK, "invoke-virtual-quick", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyVarArg) \
-  V(0xEA, INVOKE_VIRTUAL_RANGE_QUICK, "invoke-virtual/range-quick", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyVarArgRange) \
+  V(0xE3, IGET_QUICK, "iget-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xE4, IGET_WIDE_QUICK, "iget-wide-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xE5, IGET_OBJECT_QUICK, "iget-object-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xE6, IPUT_QUICK, "iput-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xE7, IPUT_WIDE_QUICK, "iput-wide-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xE8, IPUT_OBJECT_QUICK, "iput-object-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xE9, INVOKE_VIRTUAL_QUICK, "invoke-virtual-quick", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyVarArg | kVerifyRuntimeOnly) \
+  V(0xEA, INVOKE_VIRTUAL_RANGE_QUICK, "invoke-virtual/range-quick", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyVarArgRange | kVerifyRuntimeOnly) \
   V(0xEB, UNUSED_EB, "unused-eb", k10x, false, kUnknown, 0, kVerifyError) \
   V(0xEC, UNUSED_EC, "unused-ec", k10x, false, kUnknown, 0, kVerifyError) \
   V(0xED, UNUSED_ED, "unused-ed", k10x, false, kUnknown, 0, kVerifyError) \
index 63a1fe5..f551d69 100644 (file)
@@ -731,6 +731,10 @@ bool MethodVerifier::VerifyInstruction(const Instruction* inst, uint32_t code_of
       result = false;
       break;
   }
+  if (inst->GetVerifyIsRuntimeOnly() && Runtime::Current()->IsCompiler()) {
+    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "opcode only expected at runtime " << inst->Name();
+    result = false;
+  }
   return result;
 }
 
@@ -1334,31 +1338,6 @@ bool MethodVerifier::CodeFlowVerifyMethod() {
     insn_flags_[insn_idx].ClearChanged();
   }
 
-  // When we're in compiler mode, do not accept quickened instructions.
-  // We explicitly iterate over *all* instructions to check code that may be unreachable and
-  // missed by the loop above.
-  if (Runtime::Current() != nullptr && Runtime::Current()->IsCompiler()) {
-    uint32_t insn_idx = 0;
-    for (; insn_idx < insns_size; insn_idx += insn_flags_[insn_idx].GetLengthInCodeUnits()) {
-      const Instruction* inst = Instruction::At(insns + insn_idx);
-      switch (inst->Opcode()) {
-        case Instruction::IGET_QUICK:
-        case Instruction::IGET_WIDE_QUICK:
-        case Instruction::IGET_OBJECT_QUICK:
-        case Instruction::IPUT_QUICK:
-        case Instruction::IPUT_WIDE_QUICK:
-        case Instruction::IPUT_OBJECT_QUICK:
-        case Instruction::INVOKE_VIRTUAL_QUICK:
-        case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
-          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Quickened instructions not allowed. ";
-          return false;
-
-        default:
-          break;
-      }
-    }
-  }
-
   if (gDebugVerify) {
     /*
      * Scan for dead code. There's nothing "evil" about dead code