Improve how invalid references are handled

This adds a validateReference() method to the Reference interface, where
subclasses can check themselves and throw an InvalidReferenceException
This commit is contained in:
Ben Gruver 2019-07-15 15:34:13 -07:00
parent ad8f15d61d
commit 4eb5e48578
22 changed files with 502 additions and 102 deletions

View File

@ -31,18 +31,21 @@ package org.jf.baksmali.Adaptors;
import org.jf.baksmali.BaksmaliOptions;
import org.jf.dexlib2.AccessFlags;
import org.jf.dexlib2.dexbacked.DexBackedClassDef;
import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex;
import org.jf.dexlib2.iface.*;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.formats.Instruction21c;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.Reference;
import org.jf.dexlib2.util.ReferenceUtil;
import org.jf.util.IndentingWriter;
import org.jf.util.StringUtils;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.*;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class ClassDefinition {
@Nonnull public final BaksmaliOptions options;
@ -79,16 +82,14 @@ public class ClassDefinition {
case SPUT_SHORT:
case SPUT_WIDE: {
Instruction21c ins = (Instruction21c)instruction;
FieldReference fieldRef = null;
FieldReference fieldRef = (FieldReference)ins.getReference();
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));
fieldRef.validateReference();
if (fieldRef.getDefiningClass().equals((classDef.getType()))) {
fieldsSetInStaticConstructor.add(ReferenceUtil.getShortFieldDescriptor(fieldRef));
}
} catch (Reference.InvalidReferenceException ex) {
// Just ignore for now. We'll deal with it when processing the instruction
}
break;
}

View File

@ -32,12 +32,10 @@ import org.jf.baksmali.Adaptors.MethodDefinition;
import org.jf.baksmali.Adaptors.MethodDefinition.InvalidSwitchPayload;
import org.jf.baksmali.Adaptors.MethodItem;
import org.jf.baksmali.Adaptors.ReferenceFormatter;
import org.jf.baksmali.Renderers.LongRenderer;
import org.jf.baksmali.BaksmaliOptions;
import org.jf.baksmali.Renderers.LongRenderer;
import org.jf.dexlib2.Opcode;
import org.jf.dexlib2.ReferenceType;
import org.jf.dexlib2.VerificationError;
import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex;
import org.jf.dexlib2.iface.instruction.*;
import org.jf.dexlib2.iface.instruction.formats.Instruction20bc;
import org.jf.dexlib2.iface.instruction.formats.Instruction31t;
@ -81,14 +79,6 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
return opcode.isVolatileFieldAccessor() || opcode == Opcode.THROW_VERIFICATION_ERROR;
}
private String writeInvalidItemIndex(InvalidItemIndex ex, int type, IndentingWriter writer)
throws IOException {
writer.write("#");
writer.write(ex.getMessage());
writer.write("\n");
return String.format("%s@%d", ReferenceType.toString(type), ex.getInvalidIndex());
}
private interface Writable {
void writeTo(IndentingWriter writer) throws IOException;
}
@ -122,8 +112,11 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
classContext = null;
}
Reference reference = referenceInstruction.getReference();
try {
Reference reference = referenceInstruction.getReference();
reference.validateReference();
if (reference instanceof CallSiteReference) {
referenceWritable = indentingWriter -> {
ReferenceFormatter.writeCallSiteReference(indentingWriter, (CallSiteReference)reference);
@ -133,16 +126,14 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
indentingWriter.write(ReferenceUtil.getReferenceString(reference, classContext));
};
}
} catch (InvalidItemIndex ex) {
} catch (Reference.InvalidReferenceException ex) {
commentOutInstruction = true;
String referenceString = writeInvalidItemIndex(ex, referenceInstruction.getReferenceType(),
writer);
referenceWritable = indentingWriter -> writer.write(referenceString);
} catch (ReferenceType.InvalidReferenceTypeException ex) {
writer.write("#invalid reference type: ");
writer.printSignedIntAsDec(ex.getReferenceType());
commentOutInstruction = true;
referenceWritable = indentingWriter -> writer.write("invalid_reference");
writer.write("#");
writer.write(ex.getMessage());
writer.write("\n");
referenceWritable = indentingWriter -> {
indentingWriter.write(ex.getInvalidReferenceRepresentation());
};
}
if (instruction instanceof DualReferenceInstruction) {
@ -150,19 +141,19 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
(DualReferenceInstruction) instruction;
try {
Reference reference2 = dualReferenceInstruction.getReference2();
reference2.validateReference();
referenceWritable2 = indentingWriter -> {
indentingWriter.write(ReferenceUtil.getReferenceString(reference2, classContext));
};
} catch (InvalidItemIndex ex) {
} catch (Reference.InvalidReferenceException ex) {
commentOutInstruction = true;
String referenceString = writeInvalidItemIndex(ex,
dualReferenceInstruction.getReferenceType2(), writer);
referenceWritable2 = indentingWriter -> indentingWriter.write(referenceString);
} catch (ReferenceType.InvalidReferenceTypeException ex) {
writer.write("#invalid reference type: ");
writer.printSignedIntAsDec(ex.getReferenceType());
commentOutInstruction = true;
referenceWritable2 = indentingWriter -> indentingWriter.write("invalid reference");
writer.write("#");
writer.write(ex.getMessage());
writer.write("\n");
referenceWritable = indentingWriter -> {
indentingWriter.write(ex.getInvalidReferenceRepresentation());
};
}
}
}

View File

@ -40,7 +40,6 @@ import org.jf.dexlib2.ReferenceType;
import org.jf.dexlib2.analysis.AnalysisException;
import org.jf.dexlib2.analysis.AnalyzedInstruction;
import org.jf.dexlib2.analysis.MethodAnalyzer;
import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex;
import org.jf.dexlib2.iface.*;
import org.jf.dexlib2.iface.debug.DebugItem;
import org.jf.dexlib2.iface.instruction.Instruction;
@ -48,6 +47,7 @@ import org.jf.dexlib2.iface.instruction.OffsetInstruction;
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
import org.jf.dexlib2.iface.instruction.formats.Instruction31t;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.iface.reference.Reference;
import org.jf.dexlib2.immutable.instruction.ImmutableInstruction31t;
import org.jf.dexlib2.util.InstructionOffsetMap;
import org.jf.dexlib2.util.InstructionOffsetMap.InvalidInstructionOffset;
@ -437,21 +437,21 @@ public class MethodDefinition {
Opcode opcode = instruction.getOpcode();
if (opcode.referenceType == ReferenceType.METHOD) {
MethodReference methodReference = null;
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
}
MethodReference methodReference =
(MethodReference)((ReferenceInstruction)instruction).getReference();
if (methodReference != null &&
SyntheticAccessorResolver.looksLikeSyntheticAccessor(methodReference.getName())) {
AccessedMember accessedMember =
classDef.options.syntheticAccessorResolver.getAccessedMember(methodReference);
if (accessedMember != null) {
methodItems.add(new SyntheticAccessCommentMethodItem(accessedMember, currentCodeAddress));
try {
methodReference.validateReference();
if (SyntheticAccessorResolver.looksLikeSyntheticAccessor(methodReference.getName())) {
AccessedMember accessedMember =
classDef.options.syntheticAccessorResolver.getAccessedMember(methodReference);
if (accessedMember != null) {
methodItems.add(new SyntheticAccessCommentMethodItem(accessedMember, currentCodeAddress));
}
}
} catch (Reference.InvalidReferenceException e) {
// Just ignore for now. We'll deal with it when processing the instruction
}
}
}

View File

@ -0,0 +1,276 @@
/*
* Copyright 2019, 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 com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import org.jf.baksmali.Adaptors.ClassDefinition;
import org.jf.baksmali.Adaptors.Format.InstructionMethodItem;
import org.jf.baksmali.Adaptors.MethodDefinition;
import org.jf.baksmali.Adaptors.RegisterFormatter;
import org.jf.dexlib2.Format;
import org.jf.dexlib2.Opcode;
import org.jf.dexlib2.ReferenceType;
import org.jf.dexlib2.base.reference.BaseMethodReference;
import org.jf.dexlib2.base.reference.BaseStringReference;
import org.jf.dexlib2.base.reference.BaseTypeReference;
import org.jf.dexlib2.iface.*;
import org.jf.dexlib2.iface.debug.DebugItem;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.formats.Instruction21c;
import org.jf.dexlib2.iface.reference.Reference;
import org.jf.util.IndentingWriter;
import org.junit.Assert;
import org.junit.Test;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.StringWriter;
import java.util.List;
import java.util.Set;
public class InstructionMethodItemTest {
@Test
public void testInvalidReference() throws IOException {
Instruction21c instruction = new Instruction21c() {
@Override
public int getRegisterA() {
return 0;
}
@Nonnull
@Override
public Reference getReference() {
return new BaseStringReference() {
@Override
public void validateReference() throws InvalidReferenceException {
throw new InvalidReferenceException("blahblahblah");
}
@Nonnull
@Override
public String getString() {
throw new RuntimeException("invalid reference");
}
};
}
@Override
public int getReferenceType() {
return ReferenceType.STRING;
}
@Override
public Opcode getOpcode() {
return Opcode.CONST_STRING;
}
@Override
public int getCodeUnits() {
return Format.Format21c.size / 2;
}
};
MethodImplementation methodImplementation = new MethodImplementation() {
@Override
public int getRegisterCount() {
return 1;
}
@Nonnull
@Override
public Iterable<? extends Instruction> getInstructions() {
return ImmutableList.of(instruction);
}
@Nonnull
@Override
public List<? extends TryBlock<? extends ExceptionHandler>> getTryBlocks() {
return ImmutableList.of();
}
@Nonnull
@Override
public Iterable<? extends DebugItem> getDebugItems() {
return ImmutableList.of();
}
};
Method method = new TestMethod(methodImplementation);
ClassDefinition classDefinition = new ClassDefinition(
new BaksmaliOptions(), new TestClassDef());
MethodDefinition methodDefinition = new MethodDefinition(classDefinition, method, methodImplementation);
methodDefinition.registerFormatter = new RegisterFormatter(new BaksmaliOptions(), 1, 0);
InstructionMethodItem methodItem = new InstructionMethodItem<Instruction21c>(methodDefinition, 0, instruction);
StringWriter stringWriter = new StringWriter();
IndentingWriter indentingWriter = new IndentingWriter(stringWriter);
methodItem.writeTo(indentingWriter);
Assert.assertEquals("#Invalid reference\n#const-string v0, blahblahblah\nnop", stringWriter.toString());
}
private static class TestMethod extends BaseMethodReference implements Method {
private final MethodImplementation methodImplementation;
public TestMethod(MethodImplementation methodImplementation) {
this.methodImplementation = methodImplementation;
}
@Nonnull
@Override
public List<? extends MethodParameter> getParameters() {
return ImmutableList.of();
}
@Override
public int getAccessFlags() {
return 0;
}
@Nonnull
@Override
public Set<? extends Annotation> getAnnotations() {
return ImmutableSet.of();
}
@Nullable
@Override
public MethodImplementation getImplementation() {
return methodImplementation;
}
@Nonnull
@Override
public String getDefiningClass() {
return "Ltest;";
}
@Nonnull
@Override
public String getName() {
return "test";
}
@Nonnull
@Override
public List<? extends CharSequence> getParameterTypes() {
return ImmutableList.of();
}
@Nonnull
@Override
public String getReturnType() {
return "V";
}
}
private static class TestClassDef extends BaseTypeReference implements ClassDef {
@Override
public int getAccessFlags() {
return 0;
}
@Nullable
@Override
public String getSuperclass() {
return "Ljava/lang/Object;";
}
@Nonnull
@Override
public List<String> getInterfaces() {
return ImmutableList.of();
}
@Nullable
@Override
public String getSourceFile() {
return null;
}
@Nonnull
@Override
public Set<? extends Annotation> getAnnotations() {
return ImmutableSet.of();
}
@Nonnull
@Override
public Iterable<? extends Field> getStaticFields() {
return ImmutableList.of();
}
@Nonnull
@Override
public Iterable<? extends Field> getInstanceFields() {
return ImmutableList.of();
}
@Nonnull
@Override
public Iterable<? extends Field> getFields() {
return ImmutableList.of();
}
@Nonnull
@Override
public Iterable<? extends Method> getDirectMethods() {
return ImmutableList.of();
}
@Nonnull
@Override
public Iterable<? extends Method> getVirtualMethods() {
return ImmutableList.of();
}
@Nonnull
@Override
public Iterable<? extends Method> getMethods() {
return ImmutableList.of();
}
@Nonnull
@Override
public String getType() {
return "Ltest;";
}
}
}

View File

@ -44,27 +44,6 @@ public final class ReferenceType {
public static final int METHOD_HANDLE = 6;
public static final int NONE = 7;
public static String toString(int referenceType) {
switch (referenceType) {
case STRING:
return "string";
case TYPE:
return "type";
case FIELD:
return "field";
case METHOD:
return "method";
case METHOD_PROTO:
return "method_proto";
case CALL_SITE:
return "call_site";
case METHOD_HANDLE:
return "method_handle";
default:
throw new InvalidReferenceTypeException(referenceType);
}
}
public static int getReferenceType(Reference reference) {
if (reference instanceof StringReference) {
return STRING;

View File

@ -33,7 +33,7 @@ package org.jf.dexlib2.base.reference;
import org.jf.dexlib2.iface.reference.CallSiteReference;
public abstract class BaseCallSiteReference implements CallSiteReference {
public abstract class BaseCallSiteReference extends BaseReference implements CallSiteReference {
@Override
public int hashCode() {
int hashCode = getName().hashCode();

View File

@ -37,7 +37,7 @@ import org.jf.dexlib2.util.ReferenceUtil;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public abstract class BaseFieldReference implements FieldReference {
public abstract class BaseFieldReference extends BaseReference implements FieldReference {
@Override
public int hashCode() {
int hashCode = getDefiningClass().hashCode();

View File

@ -39,7 +39,7 @@ import org.jf.dexlib2.iface.reference.Reference;
import javax.annotation.Nonnull;
public abstract class BaseMethodHandleReference implements MethodHandleReference {
public abstract class BaseMethodHandleReference extends BaseReference implements MethodHandleReference {
@Override
public int hashCode() {
int hashCode = getMethodHandleType();

View File

@ -41,7 +41,7 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public abstract class BaseMethodProtoReference implements MethodProtoReference {
public abstract class BaseMethodProtoReference extends BaseReference implements MethodProtoReference {
@Override
public int hashCode() {
int hashCode = getReturnType().hashCode();

View File

@ -40,7 +40,7 @@ import org.jf.util.CollectionUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public abstract class BaseMethodReference implements MethodReference {
public abstract class BaseMethodReference extends BaseReference implements MethodReference {
@Override
public int hashCode() {
int hashCode = getDefiningClass().hashCode();

View File

@ -0,0 +1,41 @@
/*
* Copyright 2019, 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.dexlib2.base.reference;
import org.jf.dexlib2.iface.reference.Reference;
public abstract class BaseReference implements Reference {
@Override
public void validateReference() throws InvalidReferenceException {
// A reference is valid by default
}
}

View File

@ -36,7 +36,7 @@ import org.jf.dexlib2.iface.reference.StringReference;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public abstract class BaseStringReference implements StringReference {
public abstract class BaseStringReference extends BaseReference implements StringReference {
@Override
public int hashCode() {
return getString().hashCode();

View File

@ -35,7 +35,7 @@ import org.jf.dexlib2.iface.reference.TypeReference;
import javax.annotation.Nonnull;
public abstract class BaseTypeReference implements TypeReference {
public abstract class BaseTypeReference extends BaseReference implements TypeReference {
@Override
public int hashCode() {
return getType().hashCode();

View File

@ -52,8 +52,19 @@ public class DexBackedInstruction20bc extends DexBackedInstruction implements In
@Nonnull
@Override
public Reference getReference() {
int referenceType = getReferenceType();
return DexBackedReference.makeReference(dexFile, referenceType, dexFile.readUshort(instructionStart + 2));
int referenceIndex = dexFile.readUshort(instructionStart + 2);
try {
int referenceType = getReferenceType();
return DexBackedReference.makeReference(dexFile, referenceType, referenceIndex);
} catch (ReferenceType.InvalidReferenceTypeException ex) {
return new Reference() {
@Override
public void validateReference() throws InvalidReferenceException {
throw new InvalidReferenceException(String.format("%d@%d", ex.getReferenceType(), referenceIndex),
ex);
}
};
}
}
@Override public int getReferenceType() {

View File

@ -157,4 +157,11 @@ public class DexBackedCallSiteReference extends BaseCallSiteReference {
}
return callSiteOffset;
}
@Override
public void validateReference() throws InvalidReferenceException {
if (callSiteIndex < 0 || callSiteIndex >= dexFile.getCallSiteCount()) {
throw new InvalidReferenceException("callsite@" + callSiteIndex);
}
}
}

View File

@ -39,29 +39,30 @@ import javax.annotation.Nonnull;
public class DexBackedFieldReference extends BaseFieldReference {
@Nonnull public final DexBackedDexFile dexFile;
public final int fieldIdItemOffset;
private final int fieldIndex;
public DexBackedFieldReference(@Nonnull DexBackedDexFile dexFile, int fieldIndex) {
this.dexFile = dexFile;
this.fieldIdItemOffset = dexFile.getFieldIdItemOffset(fieldIndex);
this.fieldIndex = fieldIndex;
}
@Nonnull
@Override
public String getDefiningClass() {
return dexFile.getType(dexFile.readUshort(fieldIdItemOffset + FieldIdItem.CLASS_OFFSET));
return dexFile.getType(dexFile.readUshort(dexFile.getFieldIdItemOffset(fieldIndex) + FieldIdItem.CLASS_OFFSET));
}
@Nonnull
@Override
public String getName() {
return dexFile.getString(dexFile.readSmallUint(fieldIdItemOffset + FieldIdItem.NAME_OFFSET));
return dexFile.getString(dexFile.readSmallUint(dexFile.getFieldIdItemOffset(fieldIndex) +
FieldIdItem.NAME_OFFSET));
}
@Nonnull
@Override
public String getType() {
return dexFile.getType(dexFile.readUshort(fieldIdItemOffset + FieldIdItem.TYPE_OFFSET));
return dexFile.getType(dexFile.readUshort(dexFile.getFieldIdItemOffset(fieldIndex) + FieldIdItem.TYPE_OFFSET));
}
/**
@ -74,4 +75,11 @@ public class DexBackedFieldReference extends BaseFieldReference {
public int getSize() {
return FieldIdItem.ITEM_SIZE;
}
@Override
public void validateReference() throws InvalidReferenceException {
if (fieldIndex < 0 || fieldIndex >= dexFile.getFieldCount()) {
throw new InvalidReferenceException("field@" + fieldIndex);
}
}
}

View File

@ -76,4 +76,17 @@ public class DexBackedMethodHandleReference extends BaseMethodHandleReference {
throw new ExceptionWithContext("Invalid method handle type: %d", getMethodHandleType());
}
}
@Override
public void validateReference() throws InvalidReferenceException {
if (methodHandleIndex < 0 || methodHandleIndex >= dexFile.getMethodHandleCount()) {
throw new InvalidReferenceException("methodhandle@" + methodHandleIndex);
}
try {
getMemberReference();
} catch (ExceptionWithContext ex) {
throw new InvalidReferenceException("methodhandle@" + methodHandleIndex, ex);
}
}
}

View File

@ -38,22 +38,23 @@ import org.jf.dexlib2.dexbacked.raw.ProtoIdItem;
import org.jf.dexlib2.dexbacked.raw.TypeListItem;
import org.jf.dexlib2.dexbacked.util.FixedSizeList;
import java.util.List;
import javax.annotation.Nonnull;
import java.util.List;
public class DexBackedMethodProtoReference extends BaseMethodProtoReference {
@Nonnull public final DexBackedDexFile dexFile;
private final int protoIdItemOffset;
private final int protoIndex;
public DexBackedMethodProtoReference(@Nonnull DexBackedDexFile dexFile, int protoIndex) {
this.dexFile = dexFile;
this.protoIdItemOffset = dexFile.getProtoIdItemOffset(protoIndex);
this.protoIndex = protoIndex;
}
@Nonnull
@Override
public List<String> getParameterTypes() {
final int parametersOffset = dexFile.readSmallUint(protoIdItemOffset + ProtoIdItem.PARAMETERS_OFFSET);
final int parametersOffset = dexFile.readSmallUint(dexFile.getProtoIdItemOffset(protoIndex) +
ProtoIdItem.PARAMETERS_OFFSET);
if (parametersOffset > 0) {
final int parameterCount = dexFile.readSmallUint(parametersOffset + TypeListItem.SIZE_OFFSET);
final int paramListStart = parametersOffset + TypeListItem.LIST_OFFSET;
@ -72,7 +73,8 @@ public class DexBackedMethodProtoReference extends BaseMethodProtoReference {
@Nonnull
@Override
public String getReturnType() {
return dexFile.getType(dexFile.readSmallUint(protoIdItemOffset + ProtoIdItem.RETURN_TYPE_OFFSET));
return dexFile.getType(dexFile.readSmallUint(dexFile.getProtoIdItemOffset(protoIndex) +
ProtoIdItem.RETURN_TYPE_OFFSET));
}
/**
@ -90,4 +92,11 @@ public class DexBackedMethodProtoReference extends BaseMethodProtoReference {
}
return size;
}
@Override
public void validateReference() throws InvalidReferenceException {
if (protoIndex < 0 || protoIndex >= dexFile.getProtoCount()) {
throw new InvalidReferenceException("proto@" + protoIndex);
}
}
}

View File

@ -44,24 +44,26 @@ import java.util.List;
public class DexBackedMethodReference extends BaseMethodReference {
@Nonnull public final DexBackedDexFile dexFile;
public final int methodIdItemOffset;
private final int methodIndex;
private int protoIdItemOffset;
public DexBackedMethodReference(@Nonnull DexBackedDexFile dexFile, int methodIndex) {
this.dexFile = dexFile;
this.methodIdItemOffset = dexFile.getMethodIdItemOffset(methodIndex);
this.methodIndex = methodIndex;
}
@Nonnull
@Override
public String getDefiningClass() {
return dexFile.getType(dexFile.readUshort(methodIdItemOffset + MethodIdItem.CLASS_OFFSET));
return dexFile.getType(dexFile.readUshort(dexFile.getMethodIdItemOffset(methodIndex) +
MethodIdItem.CLASS_OFFSET));
}
@Nonnull
@Override
public String getName() {
return dexFile.getString(dexFile.readSmallUint(methodIdItemOffset + MethodIdItem.NAME_OFFSET));
return dexFile.getString(dexFile.readSmallUint(dexFile.getMethodIdItemOffset(methodIndex) +
MethodIdItem.NAME_OFFSET));
}
@Nonnull
@ -94,7 +96,7 @@ public class DexBackedMethodReference extends BaseMethodReference {
private int getProtoIdItemOffset() {
if (protoIdItemOffset == 0) {
protoIdItemOffset = dexFile.getProtoIdItemOffset(
dexFile.readUshort(methodIdItemOffset + MethodIdItem.PROTO_OFFSET));
dexFile.readUshort(dexFile.getMethodIdItemOffset(methodIndex) + MethodIdItem.PROTO_OFFSET));
}
return protoIdItemOffset;
}
@ -109,4 +111,11 @@ public class DexBackedMethodReference extends BaseMethodReference {
public int getSize() {
return MethodIdItem.ITEM_SIZE; //ushort + ushort + uint for indices
}
@Override
public void validateReference() throws InvalidReferenceException {
if (methodIndex < 0 || methodIndex >= dexFile.getMethodCount()) {
throw new InvalidReferenceException("method@" + methodIndex);
}
}
}

View File

@ -73,4 +73,11 @@ public class DexBackedStringReference extends BaseStringReference {
size += reader.peekStringLength(utf16Length);
return size;
}
@Override
public void validateReference() throws InvalidReferenceException {
if (stringIndex < 0 || stringIndex >= dexFile.getStringCount()) {
throw new InvalidReferenceException("string@" + stringIndex);
}
}
}

View File

@ -62,4 +62,11 @@ public class DexBackedTypeReference extends BaseTypeReference {
public int getSize() {
return TypeIdItem.ITEM_SIZE; //uint for descriptor_idx
}
@Override
public void validateReference() throws InvalidReferenceException {
if (typeIndex < 0 || typeIndex >= dexFile.getTypeCount()) {
throw new InvalidReferenceException("type@" + typeIndex);
}
}
}

View File

@ -32,8 +32,49 @@
package org.jf.dexlib2.iface.reference;
/**
* This class is the base interface for field/method/string/type references in a dex file. It has no functionality or
* contract itself.
* This class is the base interface for field/method/string/type references in a dex file.
*/
public interface Reference {
/**
* Verifies that this reference is valid.
*
* @throws InvalidReferenceException If the reference is not valid.
*/
void validateReference() throws InvalidReferenceException;
class InvalidReferenceException extends Exception {
private final String invalidReferenceRepresentation;
public InvalidReferenceException(String invalidReferenceRepresentation) {
super("Invalid reference");
this.invalidReferenceRepresentation = invalidReferenceRepresentation;
}
public InvalidReferenceException(String invalidReferenceRepresentation, String msg) {
super(msg);
this.invalidReferenceRepresentation = invalidReferenceRepresentation;
}
public InvalidReferenceException(String invalidReferenceRepresentation, String s, Throwable throwable) {
super(s, throwable);
this.invalidReferenceRepresentation = invalidReferenceRepresentation;
}
public InvalidReferenceException(String invalidReferenceRepresentation, Throwable throwable) {
super(throwable);
this.invalidReferenceRepresentation = invalidReferenceRepresentation;
}
/**
* @return A string representation of the invalid reference. This should be a human-readable string that gives
* enough information to identify the reference in question.
*
* The format of the string is not specified, although as an illustrative example "string@123" could be
* used for a reference to the string at index 123.
*/
public String getInvalidReferenceRepresentation() {
return invalidReferenceRepresentation;
}
}
}