fix: additional checks for class signature
This commit is contained in:
@@ -7,6 +7,7 @@ import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -194,6 +195,10 @@ public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeN
|
||||
root().getConstValues().processConstFields(this, staticFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Class signature format:
|
||||
* https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.9.1
|
||||
*/
|
||||
private void parseClassSignature() {
|
||||
SignatureParser sp = SignatureParser.fromNode(this);
|
||||
if (sp == null) {
|
||||
@@ -203,7 +208,7 @@ public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeN
|
||||
// parse class generic map
|
||||
generics = sp.consumeGenericTypeParameters();
|
||||
// parse super class signature
|
||||
superClass = sp.consumeType();
|
||||
superClass = validateSuperCls(sp.consumeType(), superClass);
|
||||
// parse interfaces signatures
|
||||
for (int i = 0; i < interfaces.size(); i++) {
|
||||
ArgType type = sp.consumeType();
|
||||
@@ -218,6 +223,18 @@ public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeN
|
||||
}
|
||||
}
|
||||
|
||||
private ArgType validateSuperCls(ArgType candidateType, ArgType currentType) {
|
||||
if (!candidateType.isObject()) {
|
||||
this.addComment("Incorrect class signature, super class is not object: " + SignatureParser.getSignature(this));
|
||||
return currentType;
|
||||
}
|
||||
if (Objects.equals(candidateType.getObject(), this.getClassInfo().getType().getObject())) {
|
||||
this.addComment("Incorrect class signature, super class is equals to this class: " + SignatureParser.getSignature(this));
|
||||
return currentType;
|
||||
}
|
||||
return candidateType;
|
||||
}
|
||||
|
||||
private void setFieldsTypesFromSignature() {
|
||||
for (FieldNode field : fields) {
|
||||
try {
|
||||
|
||||
@@ -33,14 +33,23 @@ public class SignatureParser {
|
||||
mark = 0;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
public static SignatureParser fromNode(IAttributeNode node) {
|
||||
String signature = getSignature(node);
|
||||
if (signature == null) {
|
||||
return null;
|
||||
}
|
||||
return new SignatureParser(signature);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
public static String getSignature(IAttributeNode node) {
|
||||
Annotation a = node.getAnnotation(Consts.DALVIK_SIGNATURE);
|
||||
if (a == null) {
|
||||
return null;
|
||||
}
|
||||
String signature = mergeSignature((List<String>) a.getDefaultValue());
|
||||
return new SignatureParser(signature);
|
||||
return mergeSignature((List<String>) a.getDefaultValue());
|
||||
}
|
||||
|
||||
private char next() {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package jadx.tests.integration.generics;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.tests.api.SmaliTest;
|
||||
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestClassSignature extends SmaliTest {
|
||||
// @formatter:off
|
||||
/*
|
||||
Incorrect class signature, super class is equals to this class: <T:Ljava/lang/Object;>Lgenerics/TestClassSignature<TT;>;
|
||||
*/
|
||||
// @formatter:on
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
assertThat(getClassNodeFromSmali())
|
||||
.code()
|
||||
.containsOne("Incorrect class signature")
|
||||
.doesNotContain("StackOverflowError");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
.class public abstract Lgenerics/TestClassSignature;
|
||||
.super Ljava/lang/Object;
|
||||
.source "SourceFile"
|
||||
|
||||
# interfaces
|
||||
.implements Ljava/util/Iterator;
|
||||
|
||||
|
||||
# annotations
|
||||
.annotation system Ldalvik/annotation/Signature;
|
||||
value = {
|
||||
"<T:",
|
||||
"Ljava/lang/Object;",
|
||||
">",
|
||||
"Lgenerics/TestClassSignature<",
|
||||
"TT;>;"
|
||||
}
|
||||
.end annotation
|
||||
|
||||
|
||||
# instance fields
|
||||
.field public f:Ljava/lang/Object;
|
||||
.annotation system Ldalvik/annotation/Signature;
|
||||
value = {
|
||||
"TT;"
|
||||
}
|
||||
.end annotation
|
||||
.end field
|
||||
|
||||
|
||||
# direct methods
|
||||
.method public constructor <init>(Ljava/lang/Object;)V
|
||||
.registers 2
|
||||
.annotation system Ldalvik/annotation/Signature;
|
||||
value = {
|
||||
"(TT;)V"
|
||||
}
|
||||
.end annotation
|
||||
|
||||
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
|
||||
iput-object p1, p0, Lgenerics/TestClassSignature;->f:Ljava/lang/Object;
|
||||
return-void
|
||||
.end method
|
||||
|
||||
|
||||
# virtual methods
|
||||
.method public abstract a(Ljava/lang/Object;)Ljava/lang/Object;
|
||||
.annotation system Ldalvik/annotation/Signature;
|
||||
value = {
|
||||
"(TT;)TT;"
|
||||
}
|
||||
.end annotation
|
||||
.end method
|
||||
|
||||
.method public final hasNext()Z
|
||||
.registers 2
|
||||
|
||||
.line 1
|
||||
iget-object v0, p0, Lgenerics/TestClassSignature;->f:Ljava/lang/Object;
|
||||
if-eqz v0, :cond_6
|
||||
const/4 v0, 0x1
|
||||
goto :goto_7
|
||||
|
||||
:cond_6
|
||||
const/4 v0, 0x0
|
||||
|
||||
:goto_7
|
||||
return v0
|
||||
.end method
|
||||
|
||||
.method public final next()Ljava/lang/Object;
|
||||
.registers 3
|
||||
.annotation system Ldalvik/annotation/Signature;
|
||||
value = {
|
||||
"()TT;"
|
||||
}
|
||||
.end annotation
|
||||
|
||||
invoke-virtual {p0}, Lgenerics/TestClassSignature;->hasNext()Z
|
||||
move-result v0
|
||||
if-eqz v0, :cond_1b
|
||||
|
||||
:try_start_6
|
||||
iget-object v0, p0, Lgenerics/TestClassSignature;->f:Ljava/lang/Object;
|
||||
:try_end_8
|
||||
.catchall {:try_start_6 .. :try_end_8} :catchall_11
|
||||
|
||||
iget-object v1, p0, Lgenerics/TestClassSignature;->f:Ljava/lang/Object;
|
||||
invoke-virtual {p0, v1}, Lgenerics/TestClassSignature;->a(Ljava/lang/Object;)Ljava/lang/Object;
|
||||
move-result-object v1
|
||||
iput-object v1, p0, Lgenerics/TestClassSignature;->f:Ljava/lang/Object;
|
||||
return-object v0
|
||||
|
||||
:catchall_11
|
||||
move-exception v0
|
||||
|
||||
iget-object v1, p0, Lgenerics/TestClassSignature;->f:Ljava/lang/Object;
|
||||
invoke-virtual {p0, v1}, Lgenerics/TestClassSignature;->a(Ljava/lang/Object;)Ljava/lang/Object;
|
||||
move-result-object v1
|
||||
iput-object v1, p0, Lgenerics/TestClassSignature;->f:Ljava/lang/Object;
|
||||
throw v0
|
||||
|
||||
:cond_1b
|
||||
new-instance v0, Ljava/util/NoSuchElementException;
|
||||
invoke-direct {v0}, Ljava/util/NoSuchElementException;-><init>()V
|
||||
throw v0
|
||||
.end method
|
||||
|
||||
.method public final remove()V
|
||||
.registers 2
|
||||
|
||||
new-instance v0, Ljava/lang/UnsupportedOperationException;
|
||||
invoke-direct {v0}, Ljava/lang/UnsupportedOperationException;-><init>()V
|
||||
throw v0
|
||||
.end method
|
||||
Reference in New Issue
Block a user