fix: handle classes 'super' loop (#1942)

This commit is contained in:
Skylot
2023-07-24 21:59:27 +01:00
parent de8c315a7a
commit 09a5e0893b
6 changed files with 68 additions and 7 deletions
@@ -199,6 +199,7 @@ public final class JadxDecompiler implements Closeable {
}
private void loadFinished() {
LOG.debug("Load finished");
List<JadxPass> list = customPasses.get(JadxAfterLoadPass.TYPE);
if (list != null) {
for (JadxPass pass : list) {
@@ -2,6 +2,7 @@ package jadx.core.dex.visitors;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -281,7 +282,7 @@ public class OverrideMethodVisitor extends AbstractVisitor {
@Nullable
private SuperTypesData collectSuperTypes(ClassNode cls) {
List<ArgType> superTypes = new ArrayList<>();
Set<ArgType> superTypes = new LinkedHashSet<>();
Set<String> endTypes = new HashSet<>();
collectSuperTypes(cls, superTypes, endTypes);
if (superTypes.isEmpty()) {
@@ -290,10 +291,10 @@ public class OverrideMethodVisitor extends AbstractVisitor {
if (endTypes.isEmpty()) {
throw new JadxRuntimeException("No end types in class hierarchy: " + cls);
}
return new SuperTypesData(superTypes, endTypes);
return new SuperTypesData(new ArrayList<>(superTypes), endTypes);
}
private void collectSuperTypes(ClassNode cls, List<ArgType> superTypes, Set<String> endTypes) {
private void collectSuperTypes(ClassNode cls, Set<ArgType> superTypes, Set<String> endTypes) {
RootNode root = cls.root();
int k = 0;
ArgType superClass = cls.getSuperClass();
@@ -308,21 +309,24 @@ public class OverrideMethodVisitor extends AbstractVisitor {
}
}
private int addSuperType(RootNode root, List<ArgType> superTypesMap, Set<String> endTypes, ArgType superType) {
private int addSuperType(RootNode root, Set<ArgType> superTypes, Set<String> endTypes, ArgType superType) {
if (Objects.equals(superType, ArgType.OBJECT)) {
return 0;
}
superTypesMap.add(superType);
if (!superTypes.add(superType)) {
// found 'super' loop, stop processing
return 0;
}
ClassNode classNode = root.resolveClass(superType);
if (classNode != null) {
collectSuperTypes(classNode, superTypesMap, endTypes);
collectSuperTypes(classNode, superTypes, endTypes);
return 1;
}
ClspClass clsDetails = root.getClsp().getClsDetails(superType);
if (clsDetails != null) {
int k = 0;
for (ArgType parentType : clsDetails.getParents()) {
k += addSuperType(root, superTypesMap, endTypes, parentType);
k += addSuperType(root, superTypes, endTypes, parentType);
}
if (k == 0) {
endTypes.add(superType.getObject());
@@ -3,8 +3,10 @@ package jadx.core.dex.visitors;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jetbrains.annotations.Nullable;
@@ -107,8 +109,14 @@ public class ShadowFieldVisitor extends AbstractVisitor {
private static List<FieldNode> collectAllInstanceFields(ClassNode cls) {
List<FieldNode> fieldsList = new ArrayList<>();
Set<ClassNode> visited = new HashSet<>();
ClassNode currentClass = cls;
while (currentClass != null) {
if (!visited.add(currentClass)) {
String msg = "Found 'super' loop in classes: " + visited;
visited.forEach(c -> c.addWarnComment(msg));
return fieldsList;
}
for (FieldNode field : currentClass.getFields()) {
if (!field.getAccessFlags().isStatic()) {
fieldsList.add(field);
@@ -0,0 +1,40 @@
package jadx.tests.integration.others;
import java.util.List;
import org.junit.jupiter.api.Test;
import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.SmaliTest;
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
@SuppressWarnings("CommentedOutCode")
public class TestSuperLoop extends SmaliTest {
// @formatter:off
/*
public class A extends B {
public int a;
}
public class B extends A {
public int b;
}
*/
// @formatter:on
@Test
public void test() {
allowWarnInCode();
disableCompilation();
List<ClassNode> clsList = loadFromSmaliFiles();
assertThat(searchCls(clsList, "A"))
.code()
.containsOne("public class A extends B {");
assertThat(searchCls(clsList, "B"))
.code()
.containsOne("public class B extends A {");
}
}
@@ -0,0 +1,4 @@
.class public LA;
.super LB;
.field public a:I
@@ -0,0 +1,4 @@
.class public LB;
.super LA;
.field public b:I