From 714b93547410746fbaebd166ad302cf135a33465 Mon Sep 17 00:00:00 2001 From: Skylot Date: Wed, 4 Nov 2020 19:03:40 +0000 Subject: [PATCH] fix: improve checks for boolean to int conversion (#921) --- .../core/dex/instructions/args/ArgType.java | 12 ++ .../dex/instructions/args/PrimitiveType.java | 4 + .../typeinference/TypeInferenceVisitor.java | 19 ++- .../types/TestPrimitiveConversion2.java | 22 +++ .../types/TestPrimitiveConversion2.smali | 128 ++++++++++++++++++ 5 files changed, 178 insertions(+), 7 deletions(-) create mode 100644 jadx-core/src/test/java/jadx/tests/integration/types/TestPrimitiveConversion2.java create mode 100644 jadx-core/src/test/smali/types/TestPrimitiveConversion2.smali diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java b/jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java index aa3b8c618..7ae233c09 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java @@ -676,6 +676,18 @@ public abstract class ArgType { || (!isTypeKnown() && contains(primitiveType)); } + public boolean canBeAnyNumber() { + if (isPrimitive()) { + return !getPrimitiveType().isObjectOrArray(); + } + for (PrimitiveType primitiveType : getPossibleTypes()) { + if (!primitiveType.isObjectOrArray()) { + return true; + } + } + return false; + } + public static ArgType convertFromPrimitiveType(PrimitiveType primitiveType) { switch (primitiveType) { case BOOLEAN: diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/args/PrimitiveType.java b/jadx-core/src/main/java/jadx/core/dex/instructions/args/PrimitiveType.java index da4a5874a..4a8bdf65f 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/args/PrimitiveType.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/args/PrimitiveType.java @@ -33,4 +33,8 @@ public enum PrimitiveType { public String toString() { return longName; } + + public boolean isObjectOrArray() { + return this == OBJECT || this == ARRAY; + } } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java index 214a5c6fe..8690e88c3 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java @@ -783,16 +783,21 @@ public final class TypeInferenceVisitor extends AbstractVisitor { if (typeInfo.getType().isTypeKnown()) { return false; } - boolean boolAssign = false; for (ITypeBound bound : typeInfo.getBounds()) { - if (bound.getBound() == BoundEnum.ASSIGN && bound.getType().equals(ArgType.BOOLEAN)) { - boolAssign = true; - break; + ArgType boundType = bound.getType(); + switch (bound.getBound()) { + case ASSIGN: + if (!boundType.contains(PrimitiveType.BOOLEAN)) { + return false; + } + break; + case USE: + if (!boundType.canBeAnyNumber()) { + return false; + } + break; } } - if (!boolAssign) { - return false; - } boolean fixed = false; for (ITypeBound bound : typeInfo.getBounds()) { diff --git a/jadx-core/src/test/java/jadx/tests/integration/types/TestPrimitiveConversion2.java b/jadx-core/src/test/java/jadx/tests/integration/types/TestPrimitiveConversion2.java new file mode 100644 index 000000000..c3364f661 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/types/TestPrimitiveConversion2.java @@ -0,0 +1,22 @@ +package jadx.tests.integration.types; + +import org.junit.jupiter.api.Test; + +import jadx.tests.api.SmaliTest; + +import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat; + +public class TestPrimitiveConversion2 extends SmaliTest { + + @Test + public void test() { + disableCompilation(); + assertThat(getClassNodeFromSmali()) + .code() + .containsOne("boolean z2 = !convertedPrice2.code.equals(itemCurrency.code);") + .doesNotContain("z2 == 0") + .doesNotContain("z2 | 2") + .containsOne("(z2 ? 1 : 0) | 2") + .containsOne("if (z2 && formatCurrency != null) {"); + } +} diff --git a/jadx-core/src/test/smali/types/TestPrimitiveConversion2.smali b/jadx-core/src/test/smali/types/TestPrimitiveConversion2.smali new file mode 100644 index 000000000..0eeccb5a9 --- /dev/null +++ b/jadx-core/src/test/smali/types/TestPrimitiveConversion2.smali @@ -0,0 +1,128 @@ +.class public Ltypes/TestPrimitiveConversion2; +.super Ljava/lang/Object; + + +.method protected test(Landroid/widget/TextView;Lapp/ItemCurrency;Lapp/ItemCurrency;Lapp/ItemCurrency;Lapp/ItemCurrency;ZLapp/SearchListItem;)Z + .locals 4 + .annotation system Ldalvik/annotation/Signature; + value = { + "(", + "Landroid/widget/TextView;", + "Lapp/ItemCurrency;", + "Lapp/ItemCurrency;", + "Lapp/ItemCurrency;", + "Lapp/ItemCurrency;", + "ZTItem;)Z" + } + .end annotation + + .line 573 + invoke-direct {p0, p2, p3}, Lapp/DefaultItemAdapter;->getConvertedPrice(Lapp/ItemCurrency;Lapp/ItemCurrency;)Lapp/ItemCurrency; + + move-result-object p3 + + const/4 v0, 0x0 + + if-eqz p3, :cond_3 + + .line 577 + iget-object v1, p3, Lapp/ItemCurrency;->code:Ljava/lang/String; + + iget-object p2, p2, Lapp/ItemCurrency;->code:Ljava/lang/String; + + invoke-virtual {v1, p2}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z + + move-result p2 + + const/4 v1, 0x1 + + xor-int/2addr p2, v1 + + or-int/lit8 v2, p2, 0x2 + + .line 581 + iget-object v3, p3, Lapp/ItemCurrency;->value:Ljava/lang/String; + + iget-object p3, p3, Lapp/ItemCurrency;->code:Ljava/lang/String; + + invoke-virtual {p0, v3, p3, v2}, Lapp/ItemAdapter;->formatCurrency(Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String; + + move-result-object p3 + + if-eqz p2, :cond_0 + + if-eqz p3, :cond_0 + + .line 586 + new-instance v1, Ljava/lang/StringBuilder; + + invoke-direct {v1}, Ljava/lang/StringBuilder;->()V + + invoke-virtual {v1, p3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + const-string p3, " " + + invoke-virtual {v1, p3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; + + move-result-object p3 + + const/4 v1, 0x2 + + :cond_0 + if-eqz p6, :cond_1 + + if-eqz p7, :cond_1 + + .line 594 + invoke-direct {p0, p4, p5}, Lapp/DefaultItemAdapter;->getConvertedPrice(Lapp/ItemCurrency;Lapp/ItemCurrency;)Lapp/ItemCurrency; + + move-result-object p5 + + if-eqz p5, :cond_1 + + .line 598 + iget-object p6, p5, Lapp/ItemCurrency;->code:Ljava/lang/String; + + iget-object p4, p4, Lapp/ItemCurrency;->code:Ljava/lang/String; + + invoke-virtual {p6, p4}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z + + move-result p4 + + .line 599 + iget-object p5, p5, Lapp/ItemCurrency;->code:Ljava/lang/String; + + invoke-direct {p0, p5, p3, p7, p4}, Lapp/DefaultItemAdapter;->getPrice(Ljava/lang/String;Ljava/lang/String;Lapp/SearchListItem;Z)Landroid/text/Spannable; + + move-result-object v0 + + :cond_1 + if-nez v0, :cond_2 + + .line 605 + sget-object p4, Landroid/graphics/Typeface;->DEFAULT:Landroid/graphics/Typeface; + + invoke-virtual {p1, p4, v1}, Landroid/widget/TextView;->setTypeface(Landroid/graphics/Typeface;I)V + + .line 606 + invoke-virtual {p1, p3}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V + + goto :goto_0 + + .line 609 + :cond_2 + invoke-virtual {p1, v0}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V + + goto :goto_0 + + .line 612 + :cond_3 + invoke-virtual {p1, v0}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V + + const/4 p2, 0x0 + + :goto_0 + return p2 +.end method