From e90f1de039b9305eed038f58db773ac2b8be36ed Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Fri, 12 Sep 2014 17:26:03 +0400 Subject: IDEA-129221 (tolerate invalid signature attributes) --- .../java/decompiler/main/ClassWriter.java | 14 +-- .../struct/gen/generics/GenericMain.java | 116 ++++++++++++--------- .../java/decompiler/SingleClassesTest.java | 42 ++++---- testData/classes/InvalidMethodSignature.class | Bin 0 -> 761 bytes testData/results/InvalidMethodSignature.dec | 26 +++++ 5 files changed, 122 insertions(+), 76 deletions(-) create mode 100644 testData/classes/InvalidMethodSignature.class create mode 100644 testData/results/InvalidMethodSignature.dec diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java index 63f60ba..856ad22 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -626,12 +626,14 @@ public class ClassWriter { StructGenericSignatureAttribute attr = (StructGenericSignatureAttribute)mt.getAttributes().getWithKey("Signature"); if (attr != null) { descriptor = GenericMain.parseMethodSignature(attr.getSignature()); - int actualParams = md.params.length; - if (isEnum && init) actualParams -= 2; - if (actualParams != descriptor.params.size()) { - String message = "Inconsistent generic signature in method " + mt.getName() + " " + mt.getDescriptor(); - DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN); - descriptor = null; + if (descriptor != null) { + int actualParams = md.params.length; + if (isEnum && init) actualParams -= 2; + if (actualParams != descriptor.params.size()) { + String message = "Inconsistent generic signature in method " + mt.getName() + " " + mt.getDescriptor(); + DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN); + descriptor = null; + } } } } diff --git a/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMain.java b/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMain.java index 065029d..3082eca 100644 --- a/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMain.java +++ b/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMain.java @@ -17,6 +17,7 @@ package org.jetbrains.java.decompiler.struct.gen.generics; import org.jetbrains.java.decompiler.code.CodeConstants; import org.jetbrains.java.decompiler.main.DecompilerContext; +import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; import org.jetbrains.java.decompiler.struct.StructClass; import java.util.ArrayList; @@ -24,7 +25,7 @@ import java.util.List; public class GenericMain { - private static final String[] typeNames = new String[]{ + private static final String[] typeNames = { "byte", "char", "double", @@ -36,63 +37,80 @@ public class GenericMain { }; public static GenericClassDescriptor parseClassSignature(String signature) { + String original = signature; + try { + GenericClassDescriptor descriptor = new GenericClassDescriptor(); - GenericClassDescriptor descriptor = new GenericClassDescriptor(); + signature = parseFormalParameters(signature, descriptor.fparameters, descriptor.fbounds); - signature = parseFormalParameters(signature, descriptor.fparameters, descriptor.fbounds); + String superCl = GenericType.getNextType(signature); + descriptor.superclass = new GenericType(superCl); - String supercl = GenericType.getNextType(signature); - descriptor.superclass = new GenericType(supercl); + signature = signature.substring(superCl.length()); + while (signature.length() > 0) { + String superIf = GenericType.getNextType(signature); + descriptor.superinterfaces.add(new GenericType(superIf)); + signature = signature.substring(superIf.length()); + } - signature = signature.substring(supercl.length()); - while (signature.length() > 0) { - String superintr = GenericType.getNextType(signature); - descriptor.superinterfaces.add(new GenericType(superintr)); - signature = signature.substring(superintr.length()); + return descriptor; + } + catch (RuntimeException e) { + DecompilerContext.getLogger().writeMessage("Invalid signature: " + original, IFernflowerLogger.Severity.WARN); + return null; } - - return descriptor; } public static GenericFieldDescriptor parseFieldSignature(String signature) { - GenericFieldDescriptor descriptor = new GenericFieldDescriptor(); - descriptor.type = new GenericType(signature); - return descriptor; + try { + GenericFieldDescriptor descriptor = new GenericFieldDescriptor(); + descriptor.type = new GenericType(signature); + return descriptor; + } + catch (RuntimeException e) { + DecompilerContext.getLogger().writeMessage("Invalid signature: " + signature, IFernflowerLogger.Severity.WARN); + return null; + } } public static GenericMethodDescriptor parseMethodSignature(String signature) { + String original = signature; + try { + GenericMethodDescriptor descriptor = new GenericMethodDescriptor(); - GenericMethodDescriptor descriptor = new GenericMethodDescriptor(); - - signature = parseFormalParameters(signature, descriptor.fparameters, descriptor.fbounds); + signature = parseFormalParameters(signature, descriptor.fparameters, descriptor.fbounds); - int to = signature.indexOf(")"); - String pars = signature.substring(1, to); - signature = signature.substring(to + 1); + int to = signature.indexOf(")"); + String pars = signature.substring(1, to); + signature = signature.substring(to + 1); - while (pars.length() > 0) { - String par = GenericType.getNextType(pars); - descriptor.params.add(new GenericType(par)); - pars = pars.substring(par.length()); - } + while (pars.length() > 0) { + String par = GenericType.getNextType(pars); + descriptor.params.add(new GenericType(par)); + pars = pars.substring(par.length()); + } - String par = GenericType.getNextType(signature); - descriptor.ret = new GenericType(par); - signature = signature.substring(par.length()); + String par = GenericType.getNextType(signature); + descriptor.ret = new GenericType(par); + signature = signature.substring(par.length()); - if (signature.length() > 0) { - String[] excs = signature.split("\\^"); + if (signature.length() > 0) { + String[] exceptions = signature.split("\\^"); - for (int i = 1; i < excs.length; i++) { - descriptor.exceptions.add(new GenericType(excs[i])); + for (int i = 1; i < exceptions.length; i++) { + descriptor.exceptions.add(new GenericType(exceptions[i])); + } } - } - return descriptor; + return descriptor; + } + catch (RuntimeException e) { + DecompilerContext.getLogger().writeMessage("Invalid signature: " + original, IFernflowerLogger.Severity.WARN); + return null; + } } - private static String parseFormalParameters(String signature, List fparameters, List> fbounds) { - + private static String parseFormalParameters(String signature, List parameters, List> bounds) { if (signature.charAt(0) != '<') { return signature; } @@ -120,10 +138,10 @@ public class GenericMain { signature = signature.substring(index + 1); while (value.length() > 0) { - int parto = value.indexOf(":"); + int to = value.indexOf(":"); - String param = value.substring(0, parto); - value = value.substring(parto + 1); + String param = value.substring(0, to); + value = value.substring(to + 1); List lstBounds = new ArrayList(); @@ -146,8 +164,8 @@ public class GenericMain { } } - fparameters.add(param); - fbounds.add(lstBounds); + parameters.add(param); + bounds.add(lstBounds); } return signature; @@ -162,8 +180,7 @@ public class GenericMain { return s; } - public static String getTypeName(GenericType type) { - + private static String getTypeName(GenericType type) { int tp = type.type; if (tp <= CodeConstants.TYPE_BOOLEAN) { return typeNames[tp]; @@ -197,9 +214,9 @@ public class GenericMain { } } - GenericType genpar = type.getArguments().get(i); - if (genpar != null) { - buffer.append(getGenericCastTypeName(genpar)); + GenericType genPar = type.getArguments().get(i); + if (genPar != null) { + buffer.append(getGenericCastTypeName(genPar)); } } buffer.append(">"); @@ -208,11 +225,10 @@ public class GenericMain { return buffer.toString(); } - throw new RuntimeException("invalid type"); + throw new RuntimeException("Invalid type: " + type); } - public static String buildJavaClassName(GenericType type) { - + private static String buildJavaClassName(GenericType type) { String name = ""; for (GenericType tp : type.getEnclosingClasses()) { name += tp.value + "$"; diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 6261591..70aa605 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -43,30 +43,32 @@ public class SingleClassesTest { fixture = null; } - @Test public void testClassFields() { doTest("TestClassFields"); } - @Test public void testClassLambda() { doTest("TestClassLambda"); } - @Test public void testClassLoop() { doTest("TestClassLoop"); } - @Test public void testClassSwitch() { doTest("TestClassSwitch"); } - @Test public void testClassTypes() { doTest("TestClassTypes"); } - @Test public void testClassVar() { doTest("TestClassVar"); } - @Test public void testClassNestedInitializer() { doTest("TestClassNestedInitializer"); } - @Test public void testClassCast() { doTest("TestClassCast"); } - @Test public void testDeprecations() { doTest("TestDeprecations"); } - @Test public void testExtendsList() { doTest("TestExtendsList"); } - @Test public void testMethodParameters() { doTest("TestMethodParameters"); } - @Test public void testCodeConstructs() { doTest("TestCodeConstructs"); } - @Test public void testConstants() { doTest("TestConstants"); } - @Test public void testEnum() { doTest("TestEnum"); } - @Test public void testDebugSymbols() { doTest("TestDebugSymbols"); } - - private void doTest(final String testName) { + @Test public void testClassFields() { doTest("pkg/TestClassFields"); } + @Test public void testClassLambda() { doTest("pkg/TestClassLambda"); } + @Test public void testClassLoop() { doTest("pkg/TestClassLoop"); } + @Test public void testClassSwitch() { doTest("pkg/TestClassSwitch"); } + @Test public void testClassTypes() { doTest("pkg/TestClassTypes"); } + @Test public void testClassVar() { doTest("pkg/TestClassVar"); } + @Test public void testClassNestedInitializer() { doTest("pkg/TestClassNestedInitializer"); } + @Test public void testClassCast() { doTest("pkg/TestClassCast"); } + @Test public void testDeprecations() { doTest("pkg/TestDeprecations"); } + @Test public void testExtendsList() { doTest("pkg/TestExtendsList"); } + @Test public void testMethodParameters() { doTest("pkg/TestMethodParameters"); } + @Test public void testCodeConstructs() { doTest("pkg/TestCodeConstructs"); } + @Test public void testConstants() { doTest("pkg/TestConstants"); } + @Test public void testEnum() { doTest("pkg/TestEnum"); } + @Test public void testDebugSymbols() { doTest("pkg/TestDebugSymbols"); } + @Test public void testInvalidMethodSignature() { doTest("InvalidMethodSignature"); } + + private void doTest(String testFile) { try { - File classFile = new File(fixture.getTestDataDir(), "/classes/pkg/" + testName + ".class"); + File classFile = new File(fixture.getTestDataDir(), "/classes/" + testFile + ".class"); assertTrue(classFile.isFile()); + String testName = classFile.getName().replace(".class", ""); ConsoleDecompiler decompiler = fixture.getDecompiler(); - for (File inner : collectClasses(classFile)) { - decompiler.addSpace(inner, true); + for (File file : collectClasses(classFile)) { + decompiler.addSpace(file, true); } decompiler.decompileContext(); diff --git a/testData/classes/InvalidMethodSignature.class b/testData/classes/InvalidMethodSignature.class new file mode 100644 index 0000000..3b64eb8 Binary files /dev/null and b/testData/classes/InvalidMethodSignature.class differ diff --git a/testData/results/InvalidMethodSignature.dec b/testData/results/InvalidMethodSignature.dec new file mode 100644 index 0000000..3b1bee4 --- /dev/null +++ b/testData/results/InvalidMethodSignature.dec @@ -0,0 +1,26 @@ +package a.a.a.a.e.f; + +import a.a.a.a.a.k; +import a.a.a.a.c.c; +import a.a.a.a.c.j; +import a.a.a.a.e.bg; +import a.a.a.a.e.f.b; +import java.io.File; + +class i implements bg { + private final j a; + private final b b; + + i(b var1, j var2) { + this.b = var1; + this.a = var2; + } + + public void a(c var1, k var2, boolean var3) { + File var4 = this.a.b().a(var1); + b.a(this.b).add(var4); + } + + public void a(a.a.a.a.c.b var1) { + } +} -- cgit v1.2.3