Add better handling for various types of invalid instructions

This commit is contained in:
Ben Gruver 2013-12-05 14:23:35 -08:00
parent 9057764c22
commit 4f2620415d
9 changed files with 235 additions and 72 deletions

View File

@ -32,6 +32,7 @@ import com.google.common.collect.Lists;
import org.jf.baksmali.baksmaliOptions; import org.jf.baksmali.baksmaliOptions;
import org.jf.dexlib2.AccessFlags; import org.jf.dexlib2.AccessFlags;
import org.jf.dexlib2.dexbacked.DexBackedClassDef; import org.jf.dexlib2.dexbacked.DexBackedClassDef;
import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex;
import org.jf.dexlib2.iface.*; import org.jf.dexlib2.iface.*;
import org.jf.dexlib2.iface.instruction.Instruction; import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.formats.Instruction21c; import org.jf.dexlib2.iface.instruction.formats.Instruction21c;
@ -79,8 +80,15 @@ public class ClassDefinition {
case SPUT_SHORT: case SPUT_SHORT:
case SPUT_WIDE: { case SPUT_WIDE: {
Instruction21c ins = (Instruction21c)instruction; Instruction21c ins = (Instruction21c)instruction;
FieldReference fieldRef = (FieldReference)ins.getReference(); FieldReference fieldRef = null;
if (fieldRef.getDefiningClass().equals((classDef.getType()))) { try {
fieldRef = (FieldReference)ins.getReference();
} catch (InvalidItemIndex ex) {
// just ignore it for now. We'll deal with it later, when processing the instructions
// themselves
}
if (fieldRef != null &&
fieldRef.getDefiningClass().equals((classDef.getType()))) {
fieldsSetInStaticConstructor.add(ReferenceUtil.getShortFieldDescriptor(fieldRef)); fieldsSetInStaticConstructor.add(ReferenceUtil.getShortFieldDescriptor(fieldRef));
} }
break; break;

View File

@ -29,16 +29,21 @@
package org.jf.baksmali.Adaptors.Format; package org.jf.baksmali.Adaptors.Format;
import org.jf.baksmali.Adaptors.MethodDefinition; import org.jf.baksmali.Adaptors.MethodDefinition;
import org.jf.baksmali.Adaptors.MethodDefinition.InvalidSwitchPayload;
import org.jf.baksmali.Adaptors.MethodItem; import org.jf.baksmali.Adaptors.MethodItem;
import org.jf.baksmali.Adaptors.ReferenceFormatter;
import org.jf.baksmali.Renderers.LongRenderer; import org.jf.baksmali.Renderers.LongRenderer;
import org.jf.baksmali.baksmaliOptions;
import org.jf.dexlib2.Opcode;
import org.jf.dexlib2.ReferenceType; import org.jf.dexlib2.ReferenceType;
import org.jf.dexlib2.VerificationError; import org.jf.dexlib2.VerificationError;
import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex; import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex;
import org.jf.dexlib2.iface.instruction.*; import org.jf.dexlib2.iface.instruction.*;
import org.jf.dexlib2.iface.instruction.formats.Instruction20bc; import org.jf.dexlib2.iface.instruction.formats.Instruction20bc;
import org.jf.dexlib2.iface.instruction.formats.Instruction31t;
import org.jf.dexlib2.iface.instruction.formats.UnknownInstruction; import org.jf.dexlib2.iface.instruction.formats.UnknownInstruction;
import org.jf.dexlib2.iface.reference.Reference; import org.jf.dexlib2.iface.reference.Reference;
import org.jf.dexlib2.util.ReferenceUtil;
import org.jf.util.ExceptionWithContext;
import org.jf.util.IndentingWriter; import org.jf.util.IndentingWriter;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -60,29 +65,105 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
return 100; return 100;
} }
private boolean isAllowedOdex(@Nonnull Opcode opcode) {
baksmaliOptions options = methodDef.classDef.options;
if (options.allowOdex) {
return true;
}
if (methodDef.classDef.options.apiLevel >= 14) {
return false;
}
return opcode.isOdexedInstanceVolatile() || opcode.isOdexedStaticVolatile() ||
opcode == Opcode.THROW_VERIFICATION_ERROR;
}
@Override @Override
public boolean writeTo(IndentingWriter writer) throws IOException { public boolean writeTo(IndentingWriter writer) throws IOException {
boolean invalidReference = false; Opcode opcode = instruction.getOpcode();
if (instruction instanceof ReferenceInstruction) { String verificationErrorName = null;
try { String referenceString = null;
Reference reference = ((ReferenceInstruction)instruction).getReference();
} catch (InvalidItemIndex ex) {
invalidReference = true;
writer.write("#invalid "); boolean commentOutInstruction = false;
writer.write(ReferenceType.toString(instruction.getOpcode().referenceType));
writer.write(" index: "); if (instruction instanceof Instruction20bc) {
writer.printSignedIntAsDec(ex.getInvalidIndex()); int verificationError = ((Instruction20bc)instruction).getVerificationError();
writer.write("\n#"); verificationErrorName = VerificationError.getVerificationErrorName(verificationError);
if (verificationErrorName == null) {
writer.write("#was invalid verification error type: ");
writer.printSignedIntAsDec(verificationError);
writer.write("\n");
verificationErrorName = "generic-error";
} }
} }
if (instruction instanceof ReferenceInstruction) {
ReferenceInstruction referenceInstruction = (ReferenceInstruction)instruction;
try {
Reference reference = referenceInstruction.getReference();
referenceString = ReferenceUtil.getReferenceString(reference);
assert referenceString != null;
} catch (InvalidItemIndex ex) {
writer.write("#");
writer.write(ex.getMessage());
writer.write("\n");
commentOutInstruction = true;
referenceString = String.format("%s@%d",
ReferenceType.toString(referenceInstruction.getReferenceType()),
ex.getInvalidIndex());
} catch (ReferenceType.InvalidReferenceTypeException ex) {
writer.write("#invalid reference type: ");
writer.printSignedIntAsDec(ex.getReferenceType());
commentOutInstruction = true;
referenceString = "invalid_reference";
}
}
if (instruction instanceof Instruction31t) {
Opcode payloadOpcode;
switch (instruction.getOpcode()) {
case PACKED_SWITCH:
payloadOpcode = Opcode.PACKED_SWITCH_PAYLOAD;
break;
case SPARSE_SWITCH:
payloadOpcode = Opcode.SPARSE_SWITCH_PAYLOAD;
break;
case FILL_ARRAY_DATA:
payloadOpcode = Opcode.ARRAY_PAYLOAD;
break;
default:
throw new ExceptionWithContext("Invalid 31t opcode: %s", instruction.getOpcode());
}
try {
methodDef.findSwitchPayload(this.codeAddress + ((Instruction31t)instruction).getCodeOffset(),
payloadOpcode);
} catch (InvalidSwitchPayload ex) {
writer.write("#invalid payload reference");
commentOutInstruction = true;
}
}
if (opcode.odexOnly()) {
if (!isAllowedOdex(opcode)) {
writer.write("#disallowed odex opcode\n");
commentOutInstruction = true;
}
}
if (commentOutInstruction) {
writer.write("#");
}
switch (instruction.getOpcode().format) { switch (instruction.getOpcode().format) {
case Format10t: case Format10t:
writeOpcode(writer); writeOpcode(writer);
writer.write(' '); writer.write(' ');
writeTargetLabel(writer); writeTargetLabel(writer);
return true; break;
case Format10x: case Format10x:
if (instruction instanceof UnknownInstruction) { if (instruction instanceof UnknownInstruction) {
writer.write("#unknown opcode: 0x"); writer.write("#unknown opcode: 0x");
@ -90,47 +171,47 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writer.write('\n'); writer.write('\n');
} }
writeOpcode(writer); writeOpcode(writer);
return true; break;
case Format11n: case Format11n:
writeOpcode(writer); writeOpcode(writer);
writer.write(' '); writer.write(' ');
writeFirstRegister(writer); writeFirstRegister(writer);
writer.write(", "); writer.write(", ");
writeLiteral(writer); writeLiteral(writer);
return true; break;
case Format11x: case Format11x:
writeOpcode(writer); writeOpcode(writer);
writer.write(' '); writer.write(' ');
writeFirstRegister(writer); writeFirstRegister(writer);
return true; break;
case Format12x: case Format12x:
writeOpcode(writer); writeOpcode(writer);
writer.write(' '); writer.write(' ');
writeFirstRegister(writer); writeFirstRegister(writer);
writer.write(", "); writer.write(", ");
writeSecondRegister(writer); writeSecondRegister(writer);
return true; break;
case Format20bc: case Format20bc:
writeOpcode(writer); writeOpcode(writer);
writer.write(' '); writer.write(' ');
writeVerificationErrorType(writer); writer.write(verificationErrorName);
writer.write(", "); writer.write(", ");
writeReference(writer); writer.write(referenceString);
return true; break;
case Format20t: case Format20t:
case Format30t: case Format30t:
writeOpcode(writer); writeOpcode(writer);
writer.write(' '); writer.write(' ');
writeTargetLabel(writer); writeTargetLabel(writer);
return true; break;
case Format21c: case Format21c:
case Format31c: case Format31c:
writeOpcode(writer); writeOpcode(writer);
writer.write(' '); writer.write(' ');
writeFirstRegister(writer); writeFirstRegister(writer);
writer.write(", "); writer.write(", ");
writeReference(writer); writer.write(referenceString);
return true; break;
case Format21ih: case Format21ih:
case Format21lh: case Format21lh:
case Format21s: case Format21s:
@ -143,7 +224,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writeLiteral(writer); writeLiteral(writer);
if (instruction.getOpcode().setsWideRegister() == false) if (instruction.getOpcode().setsWideRegister() == false)
writeResourceId(writer); writeResourceId(writer);
return true; break;
case Format21t: case Format21t:
case Format31t: case Format31t:
writeOpcode(writer); writeOpcode(writer);
@ -151,7 +232,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writeFirstRegister(writer); writeFirstRegister(writer);
writer.write(", "); writer.write(", ");
writeTargetLabel(writer); writeTargetLabel(writer);
return true; break;
case Format22b: case Format22b:
case Format22s: case Format22s:
writeOpcode(writer); writeOpcode(writer);
@ -161,7 +242,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writeSecondRegister(writer); writeSecondRegister(writer);
writer.write(", "); writer.write(", ");
writeLiteral(writer); writeLiteral(writer);
return true; break;
case Format22c: case Format22c:
writeOpcode(writer); writeOpcode(writer);
writer.write(' '); writer.write(' ');
@ -169,8 +250,8 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writer.write(", "); writer.write(", ");
writeSecondRegister(writer); writeSecondRegister(writer);
writer.write(", "); writer.write(", ");
writeReference(writer); writer.write(referenceString);
return true; break;
case Format22cs: case Format22cs:
writeOpcode(writer); writeOpcode(writer);
writer.write(' '); writer.write(' ');
@ -179,7 +260,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writeSecondRegister(writer); writeSecondRegister(writer);
writer.write(", "); writer.write(", ");
writeFieldOffset(writer); writeFieldOffset(writer);
return true; break;
case Format22t: case Format22t:
writeOpcode(writer); writeOpcode(writer);
writer.write(' '); writer.write(' ');
@ -188,7 +269,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writeSecondRegister(writer); writeSecondRegister(writer);
writer.write(", "); writer.write(", ");
writeTargetLabel(writer); writeTargetLabel(writer);
return true; break;
case Format22x: case Format22x:
case Format32x: case Format32x:
writeOpcode(writer); writeOpcode(writer);
@ -196,7 +277,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writeFirstRegister(writer); writeFirstRegister(writer);
writer.write(", "); writer.write(", ");
writeSecondRegister(writer); writeSecondRegister(writer);
return true; break;
case Format23x: case Format23x:
writeOpcode(writer); writeOpcode(writer);
writer.write(' '); writer.write(' ');
@ -205,54 +286,61 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writeSecondRegister(writer); writeSecondRegister(writer);
writer.write(", "); writer.write(", ");
writeThirdRegister(writer); writeThirdRegister(writer);
return true; break;
case Format35c: case Format35c:
writeOpcode(writer); writeOpcode(writer);
writer.write(' '); writer.write(' ');
writeInvokeRegisters(writer); writeInvokeRegisters(writer);
writer.write(", "); writer.write(", ");
writeReference(writer); writer.write(referenceString);
return true; break;
case Format35mi: case Format35mi:
writeOpcode(writer); writeOpcode(writer);
writer.write(' '); writer.write(' ');
writeInvokeRegisters(writer); writeInvokeRegisters(writer);
writer.write(", "); writer.write(", ");
writeInlineIndex(writer); writeInlineIndex(writer);
return true; break;
case Format35ms: case Format35ms:
writeOpcode(writer); writeOpcode(writer);
writer.write(' '); writer.write(' ');
writeInvokeRegisters(writer); writeInvokeRegisters(writer);
writer.write(", "); writer.write(", ");
writeVtableIndex(writer); writeVtableIndex(writer);
return true; break;
case Format3rc: case Format3rc:
writeOpcode(writer); writeOpcode(writer);
writer.write(' '); writer.write(' ');
writeInvokeRangeRegisters(writer); writeInvokeRangeRegisters(writer);
writer.write(", "); writer.write(", ");
writeReference(writer); writer.write(referenceString);
return true; break;
case Format3rmi: case Format3rmi:
writeOpcode(writer); writeOpcode(writer);
writer.write(' '); writer.write(' ');
writeInvokeRangeRegisters(writer); writeInvokeRangeRegisters(writer);
writer.write(", "); writer.write(", ");
writeInlineIndex(writer); writeInlineIndex(writer);
return true; break;
case Format3rms: case Format3rms:
writeOpcode(writer); writeOpcode(writer);
writer.write(' '); writer.write(' ');
writeInvokeRangeRegisters(writer); writeInvokeRangeRegisters(writer);
writer.write(", "); writer.write(", ");
writeVtableIndex(writer); writeVtableIndex(writer);
return true; break;
} default:
assert false; assert false;
return false; return false;
} }
if (commentOutInstruction) {
writer.write("\nnop");
}
return true;
}
protected void writeOpcode(IndentingWriter writer) throws IOException { protected void writeOpcode(IndentingWriter writer) throws IOException {
writer.write(instruction.getOpcode().name); writer.write(instruction.getOpcode().name);
} }
@ -367,20 +455,4 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
writer.write("vtable@"); writer.write("vtable@");
writer.printSignedIntAsDec(((VtableIndexInstruction)instruction).getVtableIndex()); writer.printSignedIntAsDec(((VtableIndexInstruction)instruction).getVtableIndex());
} }
protected void writeReference(IndentingWriter writer) throws IOException {
try {
ReferenceFormatter.writeReference(writer, instruction.getOpcode().referenceType,
((ReferenceInstruction)instruction).getReference());
} catch (InvalidItemIndex ex) {
writer.write(ReferenceType.toString(instruction.getOpcode().referenceType));
writer.write("@");
writer.printSignedIntAsDec(ex.getInvalidIndex());
}
}
protected void writeVerificationErrorType(IndentingWriter writer) throws IOException {
int verificationError = ((Instruction20bc)instruction).getVerificationError();
writer.write(VerificationError.getVerificationErrorName(verificationError));
}
} }

View File

@ -39,6 +39,7 @@ import org.jf.dexlib2.ReferenceType;
import org.jf.dexlib2.analysis.AnalysisException; import org.jf.dexlib2.analysis.AnalysisException;
import org.jf.dexlib2.analysis.AnalyzedInstruction; import org.jf.dexlib2.analysis.AnalyzedInstruction;
import org.jf.dexlib2.analysis.MethodAnalyzer; import org.jf.dexlib2.analysis.MethodAnalyzer;
import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex;
import org.jf.dexlib2.iface.*; import org.jf.dexlib2.iface.*;
import org.jf.dexlib2.iface.debug.DebugItem; import org.jf.dexlib2.iface.debug.DebugItem;
import org.jf.dexlib2.iface.instruction.Instruction; import org.jf.dexlib2.iface.instruction.Instruction;
@ -46,6 +47,7 @@ import org.jf.dexlib2.iface.instruction.OffsetInstruction;
import org.jf.dexlib2.iface.instruction.ReferenceInstruction; import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
import org.jf.dexlib2.iface.reference.MethodReference; import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.util.InstructionOffsetMap; import org.jf.dexlib2.util.InstructionOffsetMap;
import org.jf.dexlib2.util.InstructionOffsetMap.InvalidInstructionOffset;
import org.jf.dexlib2.util.ReferenceUtil; import org.jf.dexlib2.util.ReferenceUtil;
import org.jf.dexlib2.util.SyntheticAccessorResolver; import org.jf.dexlib2.util.SyntheticAccessorResolver;
import org.jf.dexlib2.util.TypeUtils; import org.jf.dexlib2.util.TypeUtils;
@ -92,17 +94,33 @@ public class MethodDefinition {
Opcode opcode = instruction.getOpcode(); Opcode opcode = instruction.getOpcode();
if (opcode == Opcode.PACKED_SWITCH) { if (opcode == Opcode.PACKED_SWITCH) {
boolean valid = true;
int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i); int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset(); int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
try {
targetOffset = findSwitchPayload(targetOffset, Opcode.PACKED_SWITCH_PAYLOAD); targetOffset = findSwitchPayload(targetOffset, Opcode.PACKED_SWITCH_PAYLOAD);
} catch (InvalidSwitchPayload ex) {
valid = false;
}
if (valid) {
packedSwitchMap.append(targetOffset, codeOffset); packedSwitchMap.append(targetOffset, codeOffset);
}
} else if (opcode == Opcode.SPARSE_SWITCH) { } else if (opcode == Opcode.SPARSE_SWITCH) {
boolean valid = true;
int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i); int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset(); int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
try {
targetOffset = findSwitchPayload(targetOffset, Opcode.SPARSE_SWITCH_PAYLOAD); targetOffset = findSwitchPayload(targetOffset, Opcode.SPARSE_SWITCH_PAYLOAD);
} catch (InvalidSwitchPayload ex) {
valid = false;
// The offset to the payload instruction was invalid. Nothing to do, except that we won't
// add this instruction to the map.
}
if (valid) {
sparseSwitchMap.append(targetOffset, codeOffset); sparseSwitchMap.append(targetOffset, codeOffset);
} }
} }
}
}catch (Exception ex) { }catch (Exception ex) {
String methodString; String methodString;
try { try {
@ -187,8 +205,13 @@ public class MethodDefinition {
writer.write(".end method\n"); writer.write(".end method\n");
} }
private int findSwitchPayload(int targetOffset, Opcode type) { public int findSwitchPayload(int targetOffset, Opcode type) {
int targetIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(targetOffset); int targetIndex;
try {
targetIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(targetOffset);
} catch (InvalidInstructionOffset ex) {
throw new InvalidSwitchPayload(targetOffset);
}
//TODO: does dalvik let you pad with multiple nops? //TODO: does dalvik let you pad with multiple nops?
//TODO: does dalvik let a switch instruction point to a non-payload instruction? //TODO: does dalvik let a switch instruction point to a non-payload instruction?
@ -205,7 +228,7 @@ public class MethodDefinition {
} }
} }
} }
throw new ExceptionWithContext("No switch payload at offset 0x%x", targetOffset); throw new InvalidSwitchPayload(targetOffset);
} else { } else {
return targetOffset; return targetOffset;
} }
@ -337,10 +360,16 @@ public class MethodDefinition {
Opcode opcode = instruction.getOpcode(); Opcode opcode = instruction.getOpcode();
if (opcode.referenceType == ReferenceType.METHOD) { if (opcode.referenceType == ReferenceType.METHOD) {
MethodReference methodReference = MethodReference methodReference = null;
(MethodReference)((ReferenceInstruction)instruction).getReference(); try {
methodReference = (MethodReference)((ReferenceInstruction)instruction).getReference();
} catch (InvalidItemIndex ex) {
// just ignore it for now. We'll deal with it later, when processing the instructions
// themselves
}
if (SyntheticAccessorResolver.looksLikeSyntheticAccessor(methodReference.getName())) { if (methodReference != null &&
SyntheticAccessorResolver.looksLikeSyntheticAccessor(methodReference.getName())) {
SyntheticAccessorResolver.AccessedMember accessedMember = SyntheticAccessorResolver.AccessedMember accessedMember =
classDef.options.syntheticAccessorResolver.getAccessedMember(methodReference); classDef.options.syntheticAccessorResolver.getAccessedMember(methodReference);
if (accessedMember != null) { if (accessedMember != null) {
@ -510,4 +539,17 @@ public class MethodDefinition {
return labels.values(); return labels.values();
} }
} }
public static class InvalidSwitchPayload extends ExceptionWithContext {
private final int payloadOffset;
public InvalidSwitchPayload(int payloadOffset) {
super("No switch payload at offset: %d", payloadOffset);
this.payloadOffset = payloadOffset;
}
public int getPayloadOffset() {
return payloadOffset;
}
}
} }

View File

@ -57,6 +57,9 @@ public class ReferenceFormatter {
return; return;
case ReferenceType.FIELD: case ReferenceType.FIELD:
ReferenceUtil.writeFieldDescriptor(writer, (FieldReference)reference); ReferenceUtil.writeFieldDescriptor(writer, (FieldReference)reference);
return;
default:
throw new IllegalStateException("Unknown reference type");
} }
} }
} }

View File

@ -67,6 +67,7 @@ public class baksmaliOptions {
public boolean outputDebugInfo = true; public boolean outputDebugInfo = true;
public boolean addCodeOffsets = false; public boolean addCodeOffsets = false;
public boolean noAccessorComments = false; public boolean noAccessorComments = false;
public boolean allowOdex = false;
public boolean deodex = false; public boolean deodex = false;
public boolean ignoreErrors = false; public boolean ignoreErrors = false;
public boolean checkPackagePrivateAccess = false; public boolean checkPackagePrivateAccess = false;

View File

@ -255,6 +255,7 @@ public class main {
System.err.println("Warning: You are disassembling an odex file without deodexing it. You"); System.err.println("Warning: You are disassembling an odex file without deodexing it. You");
System.err.println("won't be able to re-assemble the results unless you deodex it with the -x"); System.err.println("won't be able to re-assemble the results unless you deodex it with the -x");
System.err.println("option"); System.err.println("option");
options.allowOdex = true;
} }
} else { } else {
options.deodex = false; options.deodex = false;

View File

@ -34,6 +34,7 @@ package org.jf.dexlib2;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import org.jf.util.ExceptionWithContext; import org.jf.util.ExceptionWithContext;
import javax.annotation.Nullable;
import java.util.HashMap; import java.util.HashMap;
public class VerificationError { public class VerificationError {
@ -61,6 +62,7 @@ public class VerificationError {
verificationErrorNames.put("instantiation-error", INSTANTIATION_ERROR); verificationErrorNames.put("instantiation-error", INSTANTIATION_ERROR);
} }
@Nullable
public static String getVerificationErrorName(int verificationError) { public static String getVerificationErrorName(int verificationError) {
switch (verificationError) { switch (verificationError) {
case GENERIC: case GENERIC:

View File

@ -435,6 +435,14 @@ public class MutableMethodImplementation implements MethodImplementation {
} }
case SPARSE_SWITCH_PAYLOAD: case SPARSE_SWITCH_PAYLOAD:
case PACKED_SWITCH_PAYLOAD: case PACKED_SWITCH_PAYLOAD:
if (((BuilderSwitchPayload)instruction).referrer == null) {
// if the switch payload isn't referenced, just remove it
removeInstruction(index);
index--;
madeChanges = true;
break;
}
// intentional fall-through
case ARRAY_PAYLOAD: { case ARRAY_PAYLOAD: {
if ((location.codeAddress & 0x01) != 0) { if ((location.codeAddress & 0x01) != 0) {
int previousIndex = location.index - 1; int previousIndex = location.index - 1;

View File

@ -59,7 +59,7 @@ public class InstructionOffsetMap {
int index = Arrays.binarySearch(instructionCodeOffsets, codeOffset); int index = Arrays.binarySearch(instructionCodeOffsets, codeOffset);
if (index < 0) { if (index < 0) {
if (exact) { if (exact) {
throw new ExceptionWithContext("No instruction at offset %d", codeOffset); throw new InvalidInstructionOffset(codeOffset);
} else { } else {
// This calculation would be incorrect if index was -1 (i.e. insertion point of 0). Luckily, we can // This calculation would be incorrect if index was -1 (i.e. insertion point of 0). Luckily, we can
// ignore this case, because codeOffset will always be non-negative, and the code offset of the first // ignore this case, because codeOffset will always be non-negative, and the code offset of the first
@ -72,8 +72,34 @@ public class InstructionOffsetMap {
public int getInstructionCodeOffset(int index) { public int getInstructionCodeOffset(int index) {
if (index < 0 || index >= instructionCodeOffsets.length) { if (index < 0 || index >= instructionCodeOffsets.length) {
throw new ExceptionWithContext("Index out of bounds: %d", index); throw new InvalidInstructionIndex(index);
} }
return instructionCodeOffsets[index]; return instructionCodeOffsets[index];
} }
public static class InvalidInstructionOffset extends ExceptionWithContext {
private final int instructionOffset;
public InvalidInstructionOffset(int instructionOffset) {
super("No instruction at offset %d", instructionOffset);
this.instructionOffset = instructionOffset;
}
public int getInstructionOffset() {
return instructionOffset;
}
}
public static class InvalidInstructionIndex extends ExceptionWithContext {
private final int instructionIndex;
public InvalidInstructionIndex(int instructionIndex) {
super("Instruction index out of bounds: %d", instructionIndex);
this.instructionIndex = instructionIndex;
}
public int getInstructionIndex() {
return instructionIndex;
}
}
} }