Skip to content

Commit

Permalink
fix: add correct type propagation for check-cast and move instructions (
Browse files Browse the repository at this point in the history
  • Loading branch information
skylot committed Feb 26, 2019
1 parent ab7b6fc commit 7bd1752
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ private Map<InsnType, ITypeListener> initListenerRegistry() {
registry.put(InsnType.ARITH, this::suggestAllSameListener);
registry.put(InsnType.NEG, this::suggestAllSameListener);
registry.put(InsnType.NOT, this::suggestAllSameListener);
registry.put(InsnType.CHECK_CAST, this::checkCastListener);
return registry;
}

Expand All @@ -263,20 +264,23 @@ private TypeUpdateResult sameFirstArgListener(TypeUpdateInfo updateInfo, InsnNod
private TypeUpdateResult moveListener(TypeUpdateInfo updateInfo, InsnNode insn, InsnArg arg, ArgType candidateType) {
boolean assignChanged = isAssign(insn, arg);
InsnArg changeArg = assignChanged ? insn.getArg(0) : insn.getResult();
TypeUpdateResult result = updateTypeChecked(updateInfo, changeArg, candidateType);
if (result == REJECT && changeArg.getType().isTypeKnown()) {
boolean allowReject;
if (changeArg.getType().isTypeKnown()) {
// allow result to be wider
if (assignChanged) {
TypeCompareEnum compareTypes = comparator.compareTypes(candidateType, changeArg.getType());
if (compareTypes.isWider() && inBounds(changeArg, candidateType)) {
return CHANGED;
}
TypeCompareEnum compareTypes = comparator.compareTypes(candidateType, changeArg.getType());
boolean correctType = assignChanged ? compareTypes.isWider() : compareTypes.isNarrow();
if (correctType && inBounds(changeArg, candidateType)) {
allowReject = true;
} else {
TypeCompareEnum compareTypes = comparator.compareTypes(changeArg.getType(), candidateType);
if (compareTypes.isWider() && inBounds(changeArg, candidateType)) {
return CHANGED;
}
return REJECT;
}
} else {
allowReject = false;
}

TypeUpdateResult result = updateTypeChecked(updateInfo, changeArg, candidateType);
if (result == REJECT && allowReject) {
return CHANGED;
}
return result;
}
Expand Down Expand Up @@ -324,6 +328,15 @@ private TypeUpdateResult suggestAllSameListener(TypeUpdateInfo updateInfo, InsnN
return allSame ? SAME : CHANGED;
}

private TypeUpdateResult checkCastListener(TypeUpdateInfo updateInfo, InsnNode insn, InsnArg arg, ArgType candidateType) {
if (!isAssign(insn, arg)) {
return SAME;
}
InsnArg insnArg = insn.getArg(0);
TypeUpdateResult result = updateTypeChecked(updateInfo, insnArg, candidateType);
return result == REJECT ? SAME : result;
}

private TypeUpdateResult arrayGetListener(TypeUpdateInfo updateInfo, InsnNode insn, InsnArg arg, ArgType candidateType) {
if (isAssign(insn, arg)) {
return updateTypeChecked(updateInfo, insn.getArg(0), ArgType.array(candidateType));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package jadx.tests.integration.types;

import org.junit.Test;

import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.IntegrationTest;

import static jadx.tests.api.utils.JadxMatchers.containsOne;
import static org.junit.Assert.assertThat;

public class TestTypeResolver7 extends IntegrationTest {

public static class TestCls {
public void test(boolean a, boolean b) {
Object obj = null;
if (a) {
use(b ? (Exception) getObj() : (Exception) obj);
} else {
Runnable r = (Runnable) obj;
if (b) {
r = (Runnable) getObj();
}
use(r);
}
}

private Object getObj() {
return null;
}

private void use(Exception e) {}

private void use(Runnable r) {}
}

@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();

assertThat(code, containsOne("use(b ? (Exception) getObj() : null);"));
}

@Test
public void testNoDebug() {
noDebugInfo();
getClassNode(TestCls.class);
}
}

0 comments on commit 7bd1752

Please sign in to comment.