Projects STRLCPY jadx Commits e1b7d361
🤬
  • ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/visitors/OverrideMethodVisitor.java
    skipped 89 lines
    90 90   for (ArgType superType : superData.getSuperTypes()) {
    91 91   ClassNode classNode = mth.root().resolveClass(superType);
    92 92   if (classNode != null) {
    93  - MethodNode ovrdMth = searchOverriddenMethod(classNode, signature);
     93 + MethodNode ovrdMth = searchOverriddenMethod(classNode, mth, signature);
    94 94   if (ovrdMth != null) {
    95 95   if (isMethodVisibleInCls(ovrdMth, cls)) {
    96 96   overrideList.add(ovrdMth);
    skipped 10 lines
    107 107   Map<String, ClspMethod> methodsMap = clsDetails.getMethodsMap();
    108 108   for (Map.Entry<String, ClspMethod> entry : methodsMap.entrySet()) {
    109 109   String mthShortId = entry.getKey();
     110 + // do not check full signature, classpath methods can be trusted
     111 + // i.e. doesn't contain methods with same signature in one class
    110 112   if (mthShortId.startsWith(signature)) {
    111 113   overrideList.add(entry.getValue());
    112 114   break;
    skipped 17 lines
    130 132   }
    131 133   
    132 134   @Nullable
    133  - private MethodNode searchOverriddenMethod(ClassNode cls, String signature) {
     135 + private MethodNode searchOverriddenMethod(ClassNode cls, MethodNode mth, String signature) {
     136 + // search by exact full signature (with return value) to fight obfuscation (see test
     137 + // 'TestOverrideWithSameName')
     138 + String shortId = mth.getMethodInfo().getShortId();
    134 139   for (MethodNode supMth : cls.getMethods()) {
    135  - if (!supMth.getAccessFlags().isStatic() && supMth.getMethodInfo().getShortId().startsWith(signature)) {
     140 + if (supMth.getMethodInfo().getShortId().equals(shortId) && !supMth.getAccessFlags().isStatic()) {
    136 141   return supMth;
     142 + }
     143 + }
     144 + // search by signature without return value and check if return value is wider type
     145 + for (MethodNode supMth : cls.getMethods()) {
     146 + if (supMth.getMethodInfo().getShortId().startsWith(signature) && !supMth.getAccessFlags().isStatic()) {
     147 + TypeCompare typeCompare = cls.root().getTypeCompare();
     148 + ArgType supRetType = supMth.getMethodInfo().getReturnType();
     149 + ArgType mthRetType = mth.getMethodInfo().getReturnType();
     150 + TypeCompareEnum res = typeCompare.compareTypes(supRetType, mthRetType);
     151 + if (res.isWider()) {
     152 + return supMth;
     153 + }
     154 + if (res == TypeCompareEnum.UNKNOWN || res == TypeCompareEnum.CONFLICT) {
     155 + mth.addDebugComment("Possible override for method " + supMth.getMethodInfo().getFullId());
     156 + }
    137 157   }
    138 158   }
    139 159   return null;
    skipped 305 lines
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/test/java/jadx/tests/integration/others/TestOverrideWithSameName.java
     1 +package jadx.tests.integration.others;
     2 + 
     3 +import java.util.List;
     4 + 
     5 +import org.junit.jupiter.api.Test;
     6 + 
     7 +import jadx.core.dex.attributes.AType;
     8 +import jadx.core.dex.nodes.ClassNode;
     9 +import jadx.tests.api.SmaliTest;
     10 + 
     11 +import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
     12 + 
     13 +@SuppressWarnings("CommentedOutCode")
     14 +public class TestOverrideWithSameName extends SmaliTest {
     15 + 
     16 + //@formatter:off
     17 + /*
     18 + interface A {
     19 + B a();
     20 + C a();
     21 + }
     22 + 
     23 + abstract class B implements A {
     24 + @Override
     25 + public C a() {
     26 + return null;
     27 + }
     28 + }
     29 + 
     30 + public class C extends B {
     31 + @Override
     32 + public B a() {
     33 + return null;
     34 + }
     35 + }
     36 + */
     37 + //@formatter:on
     38 + 
     39 + @Test
     40 + public void test() {
     41 + List<ClassNode> clsNodes = loadFromSmaliFiles();
     42 + assertThat(searchCls(clsNodes, "test.A"))
     43 + .code()
     44 + .containsOne("C mo0a();") // assume second method was renamed
     45 + .doesNotContain("@Override");
     46 + 
     47 + ClassNode bCls = searchCls(clsNodes, "test.B");
     48 + assertThat(bCls)
     49 + .code()
     50 + .containsOne("C mo0a() {")
     51 + .containsOne("@Override");
     52 + 
     53 + assertThat(getMethod(bCls, "a").get(AType.METHOD_OVERRIDE).getOverrideList())
     54 + .singleElement()
     55 + .satisfies(mth -> assertThat(mth.getMethodInfo().getDeclClass().getShortName()).isEqualTo("A"));
     56 + 
     57 + ClassNode cCls = searchCls(clsNodes, "test.C");
     58 + assertThat(cCls)
     59 + .code()
     60 + .containsOne("B a() {")
     61 + .containsOne("@Override");
     62 + 
     63 + assertThat(getMethod(cCls, "a").get(AType.METHOD_OVERRIDE).getOverrideList())
     64 + .singleElement()
     65 + .satisfies(mth -> assertThat(mth.getMethodInfo().getDeclClass().getShortName()).isEqualTo("A"));
     66 + }
     67 +}
     68 + 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/test/smali/others/TestOverrideWithSameName/A.smali
     1 +.class interface abstract Ltest/A;
     2 +.super Ljava/lang/Object;
     3 + 
     4 +.method public abstract a()Ltest/B;
     5 +.end method
     6 + 
     7 +.method public abstract a()Ltest/C;
     8 +.end method
     9 + 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/test/smali/others/TestOverrideWithSameName/B.smali
     1 +.class abstract Ltest/B;
     2 +.super Ljava/lang/Object;
     3 + 
     4 +.implements Ltest/A;
     5 + 
     6 +.method public a()Ltest/C;
     7 + .registers 2
     8 + const/4 v0, 0x0
     9 + return-object v0
     10 +.end method
     11 + 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/test/smali/others/TestOverrideWithSameName/C.smali
     1 +.class public Ltest/C;
     2 +.super Ltest/B;
     3 + 
     4 +.method public a()Ltest/B;
     5 + .registers 2
     6 + const/4 v0, 0x0
     7 + return-object v0
     8 +.end method
     9 + 
Please wait...
Page is in error, reload to recover