Skip to content

Commit

Permalink
fix: add cast to exact type on field access (#729)
Browse files Browse the repository at this point in the history
  • Loading branch information
skylot committed May 29, 2020
1 parent e7b00cc commit ae31fee
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,15 @@ public String toString() {
switch (insnType) {
case CAST:
case CHECK_CAST:
return InsnUtils.formatOffset(offset) + ": "
+ InsnUtils.insnTypeToString(insnType)
+ getResult() + " = (" + InsnUtils.indexToString(index) + ") "
+ Utils.listToString(getArguments());
StringBuilder sb = new StringBuilder();
sb.append(InsnUtils.formatOffset(offset)).append(": ");
sb.append(insnType).append(' ');
if (getResult() != null) {
sb.append(getResult()).append(" = ");
}
sb.append('(').append(InsnUtils.indexToString(index)).append(") ");
sb.append(Utils.listToString(getArguments()));
return sb.toString();

default:
return super.toString() + ' ' + InsnUtils.indexToString(index);
Expand Down
5 changes: 5 additions & 0 deletions jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import jadx.core.dex.nodes.utils.TypeUtils;
import jadx.core.dex.visitors.DepthTraversal;
import jadx.core.dex.visitors.IDexTreeVisitor;
import jadx.core.dex.visitors.typeinference.TypeCompare;
import jadx.core.dex.visitors.typeinference.TypeUpdate;
import jadx.core.utils.CacheStorage;
import jadx.core.utils.ErrorsCounter;
Expand Down Expand Up @@ -424,6 +425,10 @@ public TypeUpdate getTypeUpdate() {
return typeUpdate;
}

public TypeCompare getTypeCompare() {
return typeUpdate.getTypeCompare();
}

public ICodeCache getCodeCache() {
return codeCache;
}
Expand Down
32 changes: 32 additions & 0 deletions jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import jadx.core.dex.instructions.SwitchInsn;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.InsnWrapArg;
import jadx.core.dex.instructions.args.LiteralArg;
import jadx.core.dex.instructions.args.NamedArg;
import jadx.core.dex.instructions.args.RegisterArg;
Expand All @@ -49,6 +50,7 @@
import jadx.core.dex.trycatch.ExceptionHandler;
import jadx.core.dex.visitors.regions.variables.ProcessVariables;
import jadx.core.dex.visitors.shrink.CodeShrinkVisitor;
import jadx.core.dex.visitors.typeinference.TypeCompareEnum;
import jadx.core.utils.InsnRemover;
import jadx.core.utils.InsnUtils;
import jadx.core.utils.exceptions.JadxException;
Expand Down Expand Up @@ -144,6 +146,11 @@ private static void replaceStep(MethodNode mth, InsnRemover remover) {
fixPrimitiveCast(mth, block, i, insn);
break;

case IPUT:
case IGET:
fixTypeForFieldAccess(mth, (IndexInsnNode) insn);
break;

default:
break;
}
Expand All @@ -152,6 +159,31 @@ private static void replaceStep(MethodNode mth, InsnRemover remover) {
}
}

private static void fixTypeForFieldAccess(MethodNode mth, IndexInsnNode insn) {
InsnArg instanceArg = insn.getArg(insn.getType() == InsnType.IGET ? 0 : 1);
if (instanceArg.contains(AFlag.SUPER)) {
return;
}
if (instanceArg.isInsnWrap() && ((InsnWrapArg) instanceArg).getWrapInsn().getType() == InsnType.CAST) {
return;
}
FieldInfo fieldInfo = (FieldInfo) insn.getIndex();
ArgType clsType = fieldInfo.getDeclClass().getType();
ArgType instanceType = instanceArg.getType();
TypeCompareEnum result = mth.root().getTypeCompare().compareTypes(instanceType, clsType);
if (result.isEqual() || (result == TypeCompareEnum.NARROW_BY_GENERIC && !instanceType.isGenericType())) {
return;
}
IndexInsnNode castInsn = new IndexInsnNode(InsnType.CAST, clsType, 1);
castInsn.addArg(instanceArg.duplicate());
castInsn.add(AFlag.EXPLICIT_CAST);

InsnArg castArg = InsnArg.wrapInsnIntoArg(castInsn);
castArg.setType(clsType);
insn.replaceArg(instanceArg, castArg);
InsnRemover.unbindArgUsage(mth, instanceArg);
}

private static void replaceConstKeys(ClassNode parentClass, SwitchInsn insn) {
int[] keys = insn.getKeys();
int len = keys.length;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package jadx.tests.integration.types;

import org.junit.jupiter.api.Test;

import jadx.tests.api.IntegrationTest;

import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;

public class TestFieldAccess extends IntegrationTest {

public static class TestCls {
private String field;

static <T extends TestCls> T testPut(T t) {
((TestCls) t).field = "";
return t;
}

static <T extends TestCls> T testGet(T t) {
System.out.println(((TestCls) t).field);
return t;
}
}

@Test
public void test() {
assertThat(getClassNode(TestCls.class))
.code()
.doesNotContain("t.field");
}
}

0 comments on commit ae31fee

Please sign in to comment.