core: fix incorrect float values processing

This commit is contained in:
Skylot 2013-09-28 15:17:20 +04:00
parent 00a6b6efd2
commit bd4c61d300
7 changed files with 172 additions and 20 deletions

View File

@ -41,10 +41,11 @@ public class TypeGen {
public static String literalToString(long lit, ArgType type) {
if (type == null || !type.isTypeKnown()) {
String n = Long.toString(lit);
if (Math.abs(lit) > 100)
if (Math.abs(lit) > 100) {
n += "; // 0x" + Long.toHexString(lit)
+ " float:" + Float.intBitsToFloat((int) lit)
+ " double:" + Double.longBitsToDouble(lit);
}
return n;
}

View File

@ -40,6 +40,10 @@ public abstract class ArgType {
PrimitiveType.BOOLEAN, PrimitiveType.SHORT, PrimitiveType.BYTE, PrimitiveType.CHAR,
PrimitiveType.OBJECT, PrimitiveType.ARRAY);
public static final ArgType NARROW_NUMBERS = unknown(
PrimitiveType.INT, PrimitiveType.FLOAT,
PrimitiveType.BOOLEAN, PrimitiveType.SHORT, PrimitiveType.BYTE, PrimitiveType.CHAR);
public static final ArgType WIDE = unknown(PrimitiveType.LONG, PrimitiveType.DOUBLE);
protected int hash;
@ -597,8 +601,14 @@ public abstract class ArgType {
public int getRegCount() {
if (isPrimitive()) {
PrimitiveType type = getPrimitiveType();
if (type == PrimitiveType.LONG || type == PrimitiveType.DOUBLE)
if (type == PrimitiveType.LONG || type == PrimitiveType.DOUBLE) {
return 2;
} else {
return 1;
}
}
if (!isTypeKnown()) {
return 0;
}
return 1;
}

View File

@ -8,10 +8,20 @@ public final class LiteralArg extends InsnArg {
private final long literal;
public LiteralArg(long value, ArgType type) {
if (value != 0) {
if (type.isObject()) {
throw new JadxRuntimeException("Wrong literal type: " + type + " for value: " + value);
} else if (!type.isTypeKnown()
&& !type.contains(PrimitiveType.LONG)
&& !type.contains(PrimitiveType.DOUBLE)) {
ArgType m = ArgType.merge(type, ArgType.NARROW_NUMBERS);
if (m != null) {
type = m;
}
}
}
this.literal = value;
this.typedVar = new TypedVar(type);
if (literal != 0 && type.isObject())
throw new RuntimeException("wrong literal type");
}
public long getLiteral() {

View File

@ -37,8 +37,12 @@ public class ConstInlinerVisitor extends AbstractVisitor {
private static boolean checkInsn(MethodNode mth, BlockNode block, InsnNode insn) {
if (insn.getType() == InsnType.CONST) {
InsnArg arg = insn.getArg(0);
if (arg.isLiteral()
&& insn.getResult().getType().getRegCount() == 1 /* process only narrow types */) {
if (arg.isLiteral()) {
ArgType resType = insn.getResult().getType();
// make sure arg has correct type
if (!arg.getType().isTypeKnown()) {
arg.merge(resType);
}
long lit = ((LiteralArg) arg).getLiteral();
return replaceConst(mth, block, insn, lit);
}
@ -61,17 +65,9 @@ public class ConstInlinerVisitor extends AbstractVisitor {
if (arg != insn.getResult() && !registerReassignOnPath(block, useBlock, insn)) {
// in most cases type not equal arg.getType()
// just set unknown type and run type fixer
LiteralArg litArg = InsnArg.lit(literal, ArgType.NARROW);
LiteralArg litArg = InsnArg.lit(literal, ArgType.UNKNOWN);
if (useInsn.replaceArg(arg, litArg)) {
// if (useInsn.getType() == InsnType.MOVE) {
// // 'move' became 'const'
// InsnNode constInsn = new InsnNode(mth, InsnType.CONST, 1);
// constInsn.setResult(useInsn.getResult());
// constInsn.addArg(litArg);
// ModVisitor.replaceInsn(useBlock, useInsn, constInsn);
// fixTypes(mth, constInsn);
// }
fixTypes(mth, useInsn);
fixTypes(mth, useInsn, litArg);
replace++;
}
}
@ -102,7 +98,7 @@ public class ConstInlinerVisitor extends AbstractVisitor {
* This is method similar to PostTypeResolver.visit method,
* but contains some expensive operations needed only after constant inline
*/
private static void fixTypes(MethodNode mth, InsnNode insn) {
private static void fixTypes(MethodNode mth, InsnNode insn, LiteralArg litArg) {
switch (insn.getType()) {
case CONST:
insn.getArg(0).merge(insn.getResult());
@ -120,13 +116,30 @@ public class ConstInlinerVisitor extends AbstractVisitor {
break;
}
case IF:
case IF: {
IfNode ifnode = (IfNode) insn;
if (!ifnode.isZeroCmp()) {
insn.getArg(1).merge(insn.getArg(0));
insn.getArg(0).merge(insn.getArg(1));
InsnArg arg0 = insn.getArg(0);
InsnArg arg1 = insn.getArg(1);
if (arg0 == litArg) {
arg0.merge(arg1);
} else {
arg1.merge(arg0);
}
}
break;
}
case CMP_G:
case CMP_L: {
InsnArg arg0 = insn.getArg(0);
InsnArg arg1 = insn.getArg(1);
if (arg0 == litArg) {
arg0.merge(arg1);
} else {
arg1.merge(arg0);
}
break;
}
case RETURN:
if (insn.getArgsCount() != 0) {
@ -153,6 +166,21 @@ public class ConstInlinerVisitor extends AbstractVisitor {
}
break;
case ARITH:
litArg.merge(insn.getResult());
break;
case APUT:
case AGET:
if (litArg == insn.getArg(1)) {
litArg.merge(ArgType.INT);
}
break;
case NEW_ARRAY:
litArg.merge(ArgType.INT);
break;
default:
break;
}

View File

@ -0,0 +1,30 @@
package jadx.tests.internal;
import jadx.api.InternalJadxTest;
import jadx.core.dex.nodes.ClassNode;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;
public class TestArgInline extends InternalJadxTest {
public static class TestCls {
public void method(int a) {
while (a < 10) {
int b = a + 1;
a = b;
}
}
}
//@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
System.out.println(code);
assertThat(code, not(containsString("a = a + 1;")));
assertThat(code, containsString("a++;"));
}
}

View File

@ -0,0 +1,31 @@
package jadx.tests.internal;
import jadx.api.InternalJadxTest;
import jadx.core.dex.nodes.ClassNode;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;
public class TestFloatValue extends InternalJadxTest {
public static class TestCls {
public float[] method() {
float[] fa = {0.55f};
fa[0] /= 2;
return fa;
}
}
@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
assertThat(code, not(containsString("1073741824")));
assertThat(code, containsString("0.55f;"));
assertThat(code, containsString("fa[0] = fa[0] / 2.0f;"));
}
}

View File

@ -0,0 +1,42 @@
package jadx.tests.internal;
import jadx.api.InternalJadxTest;
import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.visitors.DepthTraverser;
import jadx.core.dex.visitors.IDexTreeVisitor;
import jadx.core.utils.exceptions.DecodeException;
import java.util.List;
import org.slf4j.Logger;
public class TestVariablesDefinitions extends InternalJadxTest {
public static class TestCls {
private static Logger LOG;
private ClassNode cls;
private List<IDexTreeVisitor> passes;
public void run() {
try {
cls.load();
for (IDexTreeVisitor visitor : passes) {
DepthTraverser.visit(visitor, cls);
}
} catch (DecodeException e) {
LOG.error("Decode exception: " + cls, e);
} finally {
cls.unload();
}
}
}
//@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
System.out.println(code);
}
}