diff --git a/baksmali/src/test/java/org/jf/baksmali/LargeLocalTest.java b/baksmali/src/test/java/org/jf/baksmali/LargeLocalTest.java new file mode 100644 index 00000000..28def63d --- /dev/null +++ b/baksmali/src/test/java/org/jf/baksmali/LargeLocalTest.java @@ -0,0 +1,54 @@ +/* + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.baksmali; + +import org.junit.Test; + +/** + * Test for a bug related to debug items that refer to a register that's outside the expected range for a method + */ +public class LargeLocalTest extends IdenticalRoundtripTest { + @Test + public void testLargeEndLocal() { + runTest("LargeEndLocal"); + } + + @Test + public void testLargeRestartLocal() { + runTest("LargeRestartLocal"); + } + + @Test + public void testLargeStartLocal() { + runTest("LargeStartLocal"); + } +} diff --git a/baksmali/src/test/resources/LargeLocalTest/LargeEndLocal.smali b/baksmali/src/test/resources/LargeLocalTest/LargeEndLocal.smali new file mode 100644 index 00000000..8c7e72ce --- /dev/null +++ b/baksmali/src/test/resources/LargeLocalTest/LargeEndLocal.smali @@ -0,0 +1,11 @@ +.class LLargeRestartLocal; +.super Ljava/lang/Object; + + +# virtual methods +.method public static main([Ljava/lang/String;)V + .registers 2 + + .end local p99 + return-void +.end method diff --git a/baksmali/src/test/resources/LargeLocalTest/LargeRestartLocal.smali b/baksmali/src/test/resources/LargeLocalTest/LargeRestartLocal.smali new file mode 100644 index 00000000..41c60d02 --- /dev/null +++ b/baksmali/src/test/resources/LargeLocalTest/LargeRestartLocal.smali @@ -0,0 +1,11 @@ +.class LLargeEndLocal; +.super Ljava/lang/Object; + + +# virtual methods +.method public static main([Ljava/lang/String;)V + .registers 2 + + .restart local p99 + return-void +.end method diff --git a/baksmali/src/test/resources/LargeLocalTest/LargeStartLocal.smali b/baksmali/src/test/resources/LargeLocalTest/LargeStartLocal.smali new file mode 100644 index 00000000..b811844b --- /dev/null +++ b/baksmali/src/test/resources/LargeLocalTest/LargeStartLocal.smali @@ -0,0 +1,11 @@ +.class LLargeStartLocal; +.super Ljava/lang/Object; + + +# virtual methods +.method public static main([Ljava/lang/String;)V + .registers 2 + + .local p99, "blah":I + return-void +.end method diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/DebugInfo.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/DebugInfo.java index 8a32b5f6..ef240718 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/DebugInfo.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/util/DebugInfo.java @@ -182,7 +182,9 @@ public abstract class DebugInfo implements Iterable { String type = dexFile.getOptionalType(reader.readSmallUleb128() - 1); ImmutableStartLocal startLocal = new ImmutableStartLocal(codeAddress, register, name, type, null); - locals[register] = startLocal; + if (register >= 0 && register < locals.length) { + locals[register] = startLocal; + } return startLocal; } case DebugItemType.START_LOCAL_EXTENDED: { @@ -192,13 +194,23 @@ public abstract class DebugInfo implements Iterable { String signature = dexFile.getOptionalString(reader.readSmallUleb128() - 1); ImmutableStartLocal startLocal = new ImmutableStartLocal(codeAddress, register, name, type, signature); - locals[register] = startLocal; + if (register >= 0 && register < locals.length) { + locals[register] = startLocal; + } return startLocal; } case DebugItemType.END_LOCAL: { int register = reader.readSmallUleb128(); - LocalInfo localInfo = locals[register]; + boolean replaceLocalInTable = true; + LocalInfo localInfo; + if (register >= 0 && register < locals.length) { + localInfo = locals[register]; + } else { + localInfo = EMPTY_LOCAL_INFO; + replaceLocalInTable = false; + } + if (localInfo instanceof EndLocal) { localInfo = EMPTY_LOCAL_INFO; // don't replace the local info in locals. The new EndLocal won't have any info at all, @@ -216,11 +228,18 @@ public abstract class DebugInfo implements Iterable { } case DebugItemType.RESTART_LOCAL: { int register = reader.readSmallUleb128(); - LocalInfo localInfo = locals[register]; + LocalInfo localInfo; + if (register >= 0 && register < locals.length) { + localInfo = locals[register]; + } else { + localInfo = EMPTY_LOCAL_INFO; + } ImmutableRestartLocal restartLocal = new ImmutableRestartLocal(codeAddress, register, localInfo.getName(), localInfo.getType(), localInfo.getSignature()); - locals[register] = restartLocal; + if (register >= 0 && register < locals.length) { + locals[register] = restartLocal; + } return restartLocal; } case DebugItemType.PROLOGUE_END: {