Commit b78349ae authored by Ahmed Ashour's avatar Ahmed Ashour Committed by skylot

fix: handle boolean condition with bitwise OR and AND (#202) (PR #522)

parent eb141ad1
......@@ -7,9 +7,10 @@ import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import jadx.core.dex.instructions.ArithNode;
import jadx.core.dex.instructions.ArithOp;
import jadx.core.dex.instructions.IfNode;
import jadx.core.dex.instructions.IfOp;
import jadx.core.dex.instructions.InsnType;
import jadx.core.dex.instructions.args.InsnWrapArg;
import jadx.core.dex.instructions.args.LiteralArg;
import jadx.core.dex.instructions.args.RegisterArg;
......@@ -142,7 +143,10 @@ public final class IfCondition {
public static IfCondition simplify(IfCondition cond) {
if (cond.isCompare()) {
Compare c = cond.getCompare();
simplifyCmpOp(c);
IfCondition i = simplifyCmpOp(c);
if (i != null) {
return i;
}
if (c.getOp() == IfOp.EQ && c.getB().isLiteral() && c.getB().equals(LiteralArg.FALSE)) {
cond = not(new IfCondition(c.invert()));
} else {
......@@ -190,20 +194,53 @@ public final class IfCondition {
return cond;
}
private static void simplifyCmpOp(Compare c) {
private static IfCondition simplifyCmpOp(Compare c) {
if (!c.getA().isInsnWrap()) {
return;
return null;
}
if (!c.getB().isLiteral() || ((LiteralArg) c.getB()).getLiteral() != 0) {
return;
if (!c.getB().isLiteral()) {
return null;
}
long lit = ((LiteralArg) c.getB()).getLiteral();
if (lit != 0 && lit != 1) {
return null;
}
InsnNode wrapInsn = ((InsnWrapArg) c.getA()).getWrapInsn();
InsnType type = wrapInsn.getType();
if (type != InsnType.CMP_L && type != InsnType.CMP_G) {
return;
switch (wrapInsn.getType()) {
case CMP_L:
case CMP_G:
if (lit == 0) {
IfNode insn = c.getInsn();
insn.changeCondition(insn.getOp(), wrapInsn.getArg(0), wrapInsn.getArg(1));
}
break;
case ARITH:
ArithOp arithOp = ((ArithNode) wrapInsn).getOp();
if (arithOp == ArithOp.OR || arithOp == ArithOp.AND) {
IfOp ifOp = c.getInsn().getOp();
boolean isTrue = ifOp == IfOp.NE && lit == 0
|| ifOp == IfOp.EQ && lit == 1;
IfOp op = isTrue ? IfOp.NE : IfOp.EQ;
Mode mode = isTrue && arithOp == ArithOp.OR ||
!isTrue && arithOp == ArithOp.AND ? Mode.OR : Mode.AND;
IfNode if1 = new IfNode(op, -1, wrapInsn.getArg(0), LiteralArg.FALSE);
IfNode if2 = new IfNode(op, -1, wrapInsn.getArg(1), LiteralArg.FALSE);
return new IfCondition(mode,
Arrays.asList(new IfCondition(new Compare(if1)),
new IfCondition(new Compare(if2))));
}
break;
default:
break;
}
IfNode insn = c.getInsn();
insn.changeCondition(insn.getOp(), wrapInsn.getArg(0), wrapInsn.getArg(1));
return null;
}
public List<RegisterArg> getRegisterArgs() {
......
package jadx.tests.integration.conditions;
import org.junit.jupiter.api.Test;
import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.IntegrationTest;
import static jadx.tests.api.utils.JadxMatchers.containsOne;
import static org.hamcrest.MatcherAssert.assertThat;
public class TestBitwiseAnd extends IntegrationTest {
public static class TestCls {
private boolean a;
private boolean b;
public void test() {
if ((a & b) != false) {
test();
}
}
}
@Test
public void test() {
noDebugInfo();
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
assertThat(code, containsOne("if (this.a && this.b) {"));
}
public static class TestCls2 {
private boolean a;
private boolean b;
public void test() {
if ((a & b) != true) {
test();
}
}
}
@Test
public void test2() {
noDebugInfo();
ClassNode cls = getClassNode(TestCls2.class);
String code = cls.getCode().toString();
assertThat(code, containsOne("if (!this.a || !this.b) {"));
}
public static class TestCls3 {
private boolean a;
private boolean b;
public void test() {
if ((a & b) == false) {
test();
}
}
}
@Test
public void test3() {
noDebugInfo();
ClassNode cls = getClassNode(TestCls3.class);
String code = cls.getCode().toString();
assertThat(code, containsOne("if (!this.a || !this.b) {"));
}
public static class TestCls4 {
private boolean a;
private boolean b;
public void test() {
if ((a & b) == true) {
test();
}
}
}
@Test
public void test4() {
noDebugInfo();
ClassNode cls = getClassNode(TestCls4.class);
String code = cls.getCode().toString();
assertThat(code, containsOne("if (this.a && this.b) {"));
}
}
......@@ -2,14 +2,13 @@ package jadx.tests.integration.conditions;
import org.junit.jupiter.api.Test;
import jadx.NotYetImplemented;
import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.IntegrationTest;
import static jadx.tests.api.utils.JadxMatchers.containsOne;
import static org.hamcrest.MatcherAssert.assertThat;
public class TestConditions17 extends IntegrationTest {
public class TestBitwiseOr extends IntegrationTest {
public static class TestCls {
private boolean a;
......@@ -23,11 +22,71 @@ public class TestConditions17 extends IntegrationTest {
}
@Test
@NotYetImplemented
public void test202() {
public void test() {
noDebugInfo();
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
assertThat(code, containsOne("a || b"));
assertThat(code, containsOne("if (this.a || this.b) {"));
}
public static class TestCls2 {
private boolean a;
private boolean b;
public void test() {
if ((a | b) != true) {
test();
}
}
}
@Test
public void test2() {
noDebugInfo();
ClassNode cls = getClassNode(TestCls2.class);
String code = cls.getCode().toString();
assertThat(code, containsOne("if (!this.a && !this.b) {"));
}
public static class TestCls3 {
private boolean a;
private boolean b;
public void test() {
if ((a | b) == false) {
test();
}
}
}
@Test
public void test3() {
noDebugInfo();
ClassNode cls = getClassNode(TestCls3.class);
String code = cls.getCode().toString();
assertThat(code, containsOne("if (!this.a && !this.b) {"));
}
public static class TestCls4 {
private boolean a;
private boolean b;
public void test() {
if ((a | b) == true) {
test();
}
}
}
@Test
public void test4() {
noDebugInfo();
ClassNode cls = getClassNode(TestCls4.class);
String code = cls.getCode().toString();
assertThat(code, containsOne("if (this.a || this.b) {"));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment