fix: allow override type with wider one only from debug info (#403)
This commit is contained in:
@@ -526,6 +526,11 @@ public abstract class ArgType {
|
||||
return isArray() || (!isTypeKnown() && contains(PrimitiveType.ARRAY));
|
||||
}
|
||||
|
||||
public boolean canBePrimitive(PrimitiveType primitiveType) {
|
||||
return (isPrimitive() && getPrimitiveType() == primitiveType)
|
||||
|| (!isTypeKnown() && contains(primitiveType));
|
||||
}
|
||||
|
||||
public static ArgType convertFromPrimitiveType(PrimitiveType primitiveType) {
|
||||
switch (primitiveType) {
|
||||
case BOOLEAN:
|
||||
|
||||
@@ -9,6 +9,7 @@ import java.util.Set;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.core.Consts;
|
||||
import jadx.core.deobf.NameMapper;
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.attributes.AType;
|
||||
@@ -34,8 +35,8 @@ import jadx.core.utils.ErrorsCounter;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
|
||||
@JadxVisitor(
|
||||
name = "Debug Info Parser",
|
||||
desc = "Parse debug information (variable names and types, instruction lines)",
|
||||
name = "Debug Info Apply",
|
||||
desc = "Apply debug info to registers (type and names)",
|
||||
runAfter = {
|
||||
SSATransform.class,
|
||||
TypeInferenceVisitor.class,
|
||||
@@ -101,7 +102,7 @@ public class DebugInfoApplyVisitor extends AbstractVisitor {
|
||||
int startAddr = localVar.getStartAddr();
|
||||
int endAddr = localVar.getEndAddr();
|
||||
if (isInside(startOffset, startAddr, endAddr) || isInside(endOffset, startAddr, endAddr)) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
if (Consts.DEBUG && LOG.isDebugEnabled()) {
|
||||
LOG.debug("Apply debug info by offset for: {} to {}", ssaVar, localVar);
|
||||
}
|
||||
applyDebugInfo(mth, ssaVar, localVar.getType(), localVar.getName());
|
||||
@@ -126,15 +127,15 @@ public class DebugInfoApplyVisitor extends AbstractVisitor {
|
||||
}
|
||||
|
||||
public static void applyDebugInfo(MethodNode mth, SSAVar ssaVar, ArgType type, String varName) {
|
||||
TypeUpdateResult result = mth.root().getTypeUpdate().apply(ssaVar, type);
|
||||
if (NameMapper.isValidIdentifier(varName)) {
|
||||
ssaVar.setName(varName);
|
||||
}
|
||||
TypeUpdateResult result = mth.root().getTypeUpdate().applyDebug(ssaVar, type);
|
||||
if (result == TypeUpdateResult.REJECT) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Reject debug info of type: {} and name: '{}' for {}, mth: {}", type, varName, ssaVar, mth);
|
||||
}
|
||||
} else {
|
||||
if (NameMapper.isValidIdentifier(varName)) {
|
||||
ssaVar.setName(varName);
|
||||
}
|
||||
detachDebugInfo(ssaVar.getAssign());
|
||||
ssaVar.getUseList().forEach(DebugInfoApplyVisitor::detachDebugInfo);
|
||||
}
|
||||
|
||||
@@ -193,9 +193,6 @@ public class TypeCompare {
|
||||
return comparator;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private final class ArgTypeComparator implements Comparator<ArgType> {
|
||||
@Override
|
||||
public int compare(ArgType a, ArgType b) {
|
||||
|
||||
@@ -33,11 +33,22 @@ public final class TypeUpdate {
|
||||
private final TypeUpdateRegistry listenerRegistry;
|
||||
private final TypeCompare comparator;
|
||||
|
||||
private ThreadLocal<Boolean> applyDebug = new ThreadLocal<>();
|
||||
|
||||
public TypeUpdate(RootNode root) {
|
||||
this.listenerRegistry = initListenerRegistry();
|
||||
this.comparator = new TypeCompare(root);
|
||||
}
|
||||
|
||||
public TypeUpdateResult applyDebug(SSAVar ssaVar, ArgType candidateType) {
|
||||
try {
|
||||
applyDebug.set(true);
|
||||
return apply(ssaVar, candidateType);
|
||||
} finally {
|
||||
applyDebug.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
public TypeUpdateResult apply(SSAVar ssaVar, ArgType candidateType) {
|
||||
if (candidateType == null) {
|
||||
return REJECT;
|
||||
@@ -71,6 +82,16 @@ public final class TypeUpdate {
|
||||
if (arg.isTypeImmutable() && currentType != ArgType.UNKNOWN) {
|
||||
return REJECT;
|
||||
}
|
||||
TypeCompareEnum compareResult = comparator.compareTypes(candidateType, currentType);
|
||||
if (compareResult == TypeCompareEnum.CONFLICT) {
|
||||
return REJECT;
|
||||
}
|
||||
if (compareResult == TypeCompareEnum.WIDER || compareResult == TypeCompareEnum.WIDER_BY_GENERIC) {
|
||||
// allow wider types for apply from debug info
|
||||
if (applyDebug.get() != Boolean.TRUE) {
|
||||
return REJECT;
|
||||
}
|
||||
}
|
||||
if (arg instanceof RegisterArg) {
|
||||
RegisterArg reg = (RegisterArg) arg;
|
||||
return updateTypeForSsaVar(updateInfo, reg.getSVar(), candidateType);
|
||||
@@ -316,6 +337,14 @@ public final class TypeUpdate {
|
||||
if (candidateType.isArray() && updateArgType.canBeArray()) {
|
||||
return SAME;
|
||||
}
|
||||
if (candidateType.isPrimitive()) {
|
||||
if (updateArgType.canBePrimitive(candidateType.getPrimitiveType())) {
|
||||
return SAME;
|
||||
}
|
||||
if (updateArgType.isTypeKnown() && candidateType.getRegCount() == updateArgType.getRegCount()) {
|
||||
return SAME;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@ public class TestInlineInCatch extends IntegrationTest {
|
||||
File output = null;
|
||||
try {
|
||||
output = File.createTempFile("f", "a", dir);
|
||||
if (!output.exists()) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
} catch (Exception e) {
|
||||
if (output != null) {
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
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;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class TestPrimitivesInIf extends IntegrationTest {
|
||||
|
||||
public static class TestCls {
|
||||
|
||||
public boolean test(String str) {
|
||||
short sh = Short.parseShort(str);
|
||||
int i = Integer.parseInt(str);
|
||||
System.out.println(sh + " vs " + i);
|
||||
return sh == i;
|
||||
}
|
||||
|
||||
public void check() {
|
||||
assertTrue(test("1"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
assertThat(code, containsOne("short sh = Short.parseShort(str);"));
|
||||
assertThat(code, containsOne("int i = Integer.parseInt(str);"));
|
||||
assertThat(code, containsOne("return sh == i;"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2() {
|
||||
setOutputCFG();
|
||||
noDebugInfo();
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
assertThat(code, containsOne("short parseShort = Short.parseShort(str);"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user