mirror of
https://github.com/skylot/jadx.git
synced 2024-11-30 08:00:47 +00:00
core: fix incorrect float values processing
This commit is contained in:
parent
00a6b6efd2
commit
bd4c61d300
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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++;"));
|
||||
}
|
||||
}
|
@ -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;"));
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user