fix: additional checks for class signature

This commit is contained in:
Skylot
2020-03-22 12:11:58 +00:00
parent dbd00d5a8b
commit e09e933f9c
4 changed files with 168 additions and 4 deletions
@@ -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