mirror of
https://github.com/revanced/smali.git
synced 2025-05-12 04:14:27 +02:00
Handle uninitialized referenced appropriately
git-svn-id: https://smali.googlecode.com/svn/trunk@610 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
parent
b615ba6f51
commit
a0314c265e
@ -1,6 +1,9 @@
|
||||
package org.jf.dexlib.Code.Analysis;
|
||||
|
||||
import org.jf.dexlib.Code.*;
|
||||
import org.jf.dexlib.Item;
|
||||
import org.jf.dexlib.ItemType;
|
||||
import org.jf.dexlib.MethodIdItem;
|
||||
import org.jf.dexlib.Util.ExceptionWithContext;
|
||||
|
||||
import java.util.LinkedList;
|
||||
@ -100,6 +103,23 @@ public class AnalyzedInstruction {
|
||||
return mergedRegisterType;
|
||||
}
|
||||
|
||||
protected boolean isInvokeInit() {
|
||||
if (instruction.opcode != Opcode.INVOKE_DIRECT && instruction.opcode != Opcode.INVOKE_DIRECT_RANGE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
InstructionWithReference instruction = (InstructionWithReference)this.instruction;
|
||||
Item item = instruction.getReferencedItem();
|
||||
assert item.getItemType() == ItemType.TYPE_METHOD_ID_ITEM;
|
||||
MethodIdItem method = (MethodIdItem)item;
|
||||
|
||||
if (!method.getMethodName().equals("<init>")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean setsRegister() {
|
||||
return instruction.opcode.setsRegister();
|
||||
}
|
||||
@ -109,10 +129,33 @@ public class AnalyzedInstruction {
|
||||
}
|
||||
|
||||
public boolean setsRegister(int registerNumber) {
|
||||
|
||||
//When constructing a new object, the register type will be an uninitialized reference after the new-instance
|
||||
//instruction, but becomes an initialized reference once the <init> method is called. So even though invoke
|
||||
//instructions don't normally change any registers, calling an <init> method will change the type of its
|
||||
//object register. If the uninitialized reference has been copied to other registers, they will be initialized
|
||||
//as well, so we need to check for that too
|
||||
if (isInvokeInit()) {
|
||||
int destinationRegister = ((FiveRegisterInstruction)instruction).getRegisterD();
|
||||
if (registerNumber == destinationRegister) {
|
||||
return true;
|
||||
}
|
||||
RegisterType preInstructionDestRegisterType = getMergedRegisterTypeFromPredecessors(destinationRegister);
|
||||
if (preInstructionDestRegisterType.category != RegisterType.Category.UninitRef) {
|
||||
return false;
|
||||
}
|
||||
//check if the uninit ref has been copied to another register
|
||||
if (getMergedRegisterTypeFromPredecessors(registerNumber) == preInstructionDestRegisterType) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!setsRegister()) {
|
||||
return false;
|
||||
}
|
||||
int destinationRegister = getDestinationRegister();
|
||||
|
||||
if (registerNumber == destinationRegister) {
|
||||
return true;
|
||||
}
|
||||
|
@ -1024,6 +1024,28 @@ public class MethodAnalyzer {
|
||||
private boolean handleNewInstance(AnalyzedInstruction analyzedInstruction) {
|
||||
InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
|
||||
|
||||
int register = ((SingleRegisterInstruction)analyzedInstruction.instruction).getRegisterA();
|
||||
RegisterType destRegisterType = analyzedInstruction.postRegisterMap[register];
|
||||
if (destRegisterType.category != RegisterType.Category.Unknown) {
|
||||
assert destRegisterType.category == RegisterType.Category.UninitRef;
|
||||
|
||||
//the "post-instruction" destination register will only be set if we've gone over
|
||||
//this instruction at least once before. If this is the case, then we need to check
|
||||
//all the other registers, and make sure that none of them contain the same
|
||||
//uninitialized reference that is in the destination register.
|
||||
|
||||
for (int i=0; i<analyzedInstruction.postRegisterMap.length; i++) {
|
||||
if (i==register) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (analyzedInstruction.getPreInstructionRegisterType(i) == destRegisterType) {
|
||||
throw new ValidationException(String.format("Register v%d contains an uninitialized reference " +
|
||||
"that was created by this new-instance instruction.", i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item item = instruction.getReferencedItem();
|
||||
assert item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
|
||||
|
||||
@ -1036,7 +1058,7 @@ public class MethodAnalyzer {
|
||||
}
|
||||
|
||||
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
|
||||
RegisterType.getRegisterType(RegisterType.Category.UninitRef, classType.type));
|
||||
RegisterType.getUnitializedReference(classType.type));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -95,7 +95,7 @@ public class RegisterType {
|
||||
/*LongHi*/ {Unknown, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, LongHi, Conflicted, LongHi, Conflicted, Conflicted, Conflicted},
|
||||
/*DoubleLo*/ {Unknown, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, LongLo, Conflicted, DoubleLo, Conflicted, Conflicted, Conflicted, Conflicted},
|
||||
/*DoubleHi*/ {Unknown, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, LongHi, Conflicted, DoubleHi, Conflicted, Conflicted, Conflicted},
|
||||
/*UninitRef*/ {Unknown, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, UninitRef, Conflicted, Conflicted},
|
||||
/*UninitRef*/ {Unknown, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted},
|
||||
/*Reference*/ {Unknown, Reference, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Reference, Conflicted},
|
||||
/*Conflicted*/ {Unknown, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted, Conflicted}
|
||||
};
|
||||
@ -251,6 +251,14 @@ public class RegisterType {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static RegisterType getUnitializedReference(ClassDef classType) {
|
||||
//We always create a new RegisterType instance for an uninit ref. Each unique uninit RegisterType instance
|
||||
//is used to track a specific uninitialized reference, so that if multiple registers contain the same
|
||||
//uninitialized reference, then they can all be upgraded to an initialized reference when the appropriate
|
||||
//<init> is invoked
|
||||
return new RegisterType(Category.UninitRef, classType);
|
||||
}
|
||||
|
||||
public static RegisterType getRegisterType(Category category, ClassDef classType) {
|
||||
RegisterType newRegisterType = new RegisterType(category, classType);
|
||||
RegisterType internedRegisterType = internedRegisterTypes.get(newRegisterType);
|
||||
|
Loading…
x
Reference in New Issue
Block a user