mirror of
https://github.com/revanced/smali.git
synced 2025-05-15 05:37:05 +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;
|
package org.jf.dexlib.Code.Analysis;
|
||||||
|
|
||||||
import org.jf.dexlib.Code.*;
|
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 org.jf.dexlib.Util.ExceptionWithContext;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@ -100,6 +103,23 @@ public class AnalyzedInstruction {
|
|||||||
return mergedRegisterType;
|
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() {
|
public boolean setsRegister() {
|
||||||
return instruction.opcode.setsRegister();
|
return instruction.opcode.setsRegister();
|
||||||
}
|
}
|
||||||
@ -109,10 +129,33 @@ public class AnalyzedInstruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean setsRegister(int registerNumber) {
|
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()) {
|
if (!setsRegister()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int destinationRegister = getDestinationRegister();
|
int destinationRegister = getDestinationRegister();
|
||||||
|
|
||||||
if (registerNumber == destinationRegister) {
|
if (registerNumber == destinationRegister) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1024,6 +1024,28 @@ public class MethodAnalyzer {
|
|||||||
private boolean handleNewInstance(AnalyzedInstruction analyzedInstruction) {
|
private boolean handleNewInstance(AnalyzedInstruction analyzedInstruction) {
|
||||||
InstructionWithReference instruction = (InstructionWithReference)analyzedInstruction.instruction;
|
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();
|
Item item = instruction.getReferencedItem();
|
||||||
assert item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
|
assert item.getItemType() == ItemType.TYPE_TYPE_ID_ITEM;
|
||||||
|
|
||||||
@ -1036,7 +1058,7 @@ public class MethodAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
|
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction,
|
||||||
RegisterType.getRegisterType(RegisterType.Category.UninitRef, classType.type));
|
RegisterType.getUnitializedReference(classType.type));
|
||||||
return true;
|
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},
|
/*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},
|
/*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},
|
/*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},
|
/*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}
|
/*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;
|
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) {
|
public static RegisterType getRegisterType(Category category, ClassDef classType) {
|
||||||
RegisterType newRegisterType = new RegisterType(category, classType);
|
RegisterType newRegisterType = new RegisterType(category, classType);
|
||||||
RegisterType internedRegisterType = internedRegisterTypes.get(newRegisterType);
|
RegisterType internedRegisterType = internedRegisterTypes.get(newRegisterType);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user