OSDN Git Service

Fix verification of switch offsets in large methods.
authorAndy McFadden <fadden@android.com>
Tue, 28 Sep 2010 20:58:16 +0000 (13:58 -0700)
committerAndy McFadden <fadden@android.com>
Tue, 28 Sep 2010 21:01:03 +0000 (14:01 -0700)
The verifier was only using the low 16 bits when checking the offset
to a switch table.  This was failing on really large methods.

We also blew up the arbitrary size cap again, so I made it a warning
rather than a failure (it really wasn't doing anybody any good).

Changed to width-specific types for the various offsets and sizes.

Bug 3044850.

Change-Id: I42902218775a9f3c970d8a0db78c10b73153d100

vm/analysis/CodeVerify.c
vm/analysis/VerifySubs.c

index 042b4c0..933c058 100644 (file)
@@ -3094,11 +3094,10 @@ bool dvmVerifyCodeFlow(VerifierData* vdata)
             dvmFindSystemClassNoInit("Ljava/lang/Object;");
 
     if (meth->registersSize * insnsSize > 4*1024*1024) {
-        /* should probably base this on actual memory requirements */
         LOG_VFY_METH(meth,
-            "VFY: arbitrarily rejecting large method (regs=%d count=%d)\n",
+            "VFY: warning: method is huge (regs=%d insnsSize=%d)\n",
             meth->registersSize, insnsSize);
-        goto bail;
+        /* might be bogus data, might be some huge generated method */
     }
 
     /*
index 2285aef..a060d2a 100644 (file)
@@ -176,18 +176,19 @@ bool dvmSetTryFlags(const Method* meth, InsnFlags* insnFlags)
 bool dvmCheckSwitchTargets(const Method* meth, InsnFlags* insnFlags,
     int curOffset)
 {
-    const int insnCount = dvmGetMethodInsnsSize(meth);
+    const s4 insnCount = dvmGetMethodInsnsSize(meth);
     const u2* insns = meth->insns + curOffset;
     const u2* switchInsns;
     u2 expectedSignature;
-    int switchCount, tableSize;
-    int offsetToSwitch, offsetToKeys, offsetToTargets, targ;
-    int offset, absOffset;
+    u4 switchCount, tableSize;
+    s4 offsetToSwitch, offsetToKeys, offsetToTargets;
+    s4 offset, absOffset;
+    u4 targ;
 
     assert(curOffset >= 0 && curOffset < insnCount);
 
     /* make sure the start of the switch is in range */
-    offsetToSwitch = (s2) insns[1];
+    offsetToSwitch = insns[1] | ((s4) insns[2]) << 16;
     if (curOffset + offsetToSwitch < 0 ||
         curOffset + offsetToSwitch + 2 >= insnCount)
     {