From a74a9d7d2537c2e21adc94c6126369c703ea7e80 Mon Sep 17 00:00:00 2001 From: Maxim Degtyarev Date: Fri, 27 Apr 2018 15:01:55 +0300 Subject: [PATCH] Fix NPE when decompiling constructor #654 --- .../modules/decompiler/exps/ExprUtil.java | 11 ++-- .../java/decompiler/SingleClassesTest.java | 3 + .../pkg/TestMissingConstructorCallBad.class | Bin 0 -> 641 bytes .../pkg/TestMissingConstructorCallGood.class | Bin 0 -> 699 bytes .../results/TestMissingConstructorCallBad.dec | 50 +++++++++++++++ .../TestMissingConstructorCallGood.dec | 60 ++++++++++++++++++ .../pkg/TestMissingConstructorCallBad.jasm | 42 ++++++++++++ .../pkg/TestMissingConstructorCallGood.jasm | 50 +++++++++++++++ 8 files changed, 212 insertions(+), 4 deletions(-) create mode 100644 testData/classes/pkg/TestMissingConstructorCallBad.class create mode 100644 testData/classes/pkg/TestMissingConstructorCallGood.class create mode 100644 testData/results/TestMissingConstructorCallBad.dec create mode 100644 testData/results/TestMissingConstructorCallGood.dec create mode 100644 testData/src/pkg/TestMissingConstructorCallBad.jasm create mode 100644 testData/src/pkg/TestMissingConstructorCallGood.jasm diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExprUtil.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExprUtil.java index 90c6d90..b044570 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExprUtil.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExprUtil.java @@ -1,12 +1,11 @@ -/* - * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.java.decompiler.modules.decompiler.exps; import org.jetbrains.java.decompiler.code.CodeConstants; import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode; import org.jetbrains.java.decompiler.main.DecompilerContext; import org.jetbrains.java.decompiler.main.rels.ClassWrapper; +import org.jetbrains.java.decompiler.main.rels.MethodWrapper; import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; import java.util.ArrayList; @@ -25,7 +24,11 @@ public class ExprUtil { ClassWrapper wrapper = node.getWrapper(); if (wrapper != null) { // own class - mask = wrapper.getMethodWrapper(CodeConstants.INIT_NAME, descriptor).synthParameters; + MethodWrapper methodWrapper = wrapper.getMethodWrapper(CodeConstants.INIT_NAME, descriptor); + if (methodWrapper == null) { + return null; + } + mask = methodWrapper.synthParameters; } else if (parameters > 0 && node.type == ClassNode.CLASS_MEMBER && (node.access & CodeConstants.ACC_STATIC) == 0) { // non-static member class diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 22d6cb4..b9a6e4e 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -104,6 +104,9 @@ public class SingleClassesTest { @Test public void testPop2TwoIntPop2() { doTest("pkg/TestPop2TwoIntPop2"); } @Test public void testPop2TwoIntTwoPop() { doTest("pkg/TestPop2TwoIntTwoPop"); } @Test public void testSuperInner() { doTest("pkg/TestSuperInner", "pkg/TestSuperInnerBase"); } + @Test public void testMissingConstructorCallGood() { doTest("pkg/TestMissingConstructorCallGood"); } + @Test public void testMissingConstructorCallBad() { doTest("pkg/TestMissingConstructorCallBad"); } + // TODO: fix all below //@Test public void testPackageInfo() { doTest("pkg/package-info"); } diff --git a/testData/classes/pkg/TestMissingConstructorCallBad.class b/testData/classes/pkg/TestMissingConstructorCallBad.class new file mode 100644 index 0000000000000000000000000000000000000000..4c73fb14693d97dc07c3243908d5bac2c9359ef1 GIT binary patch literal 641 zcmaKp&rae{6vn>`l?$~9;^;X3qiBriLN@L+E{4R7_$OjC#?=LGG{s@`)<$2=j%Iw9jv8Mw2^|7!3uswZwodS;c{dcR?lT< zj#L;b|E8+_&;J?foOP= zA+@J`W%eCRB26^iH-D8%S55=vo4N_4Ag9@KZA3U}bY#=)M&5Q^_k*T9P!TRalGN`* zBfrlPj7}5JW$Q*XZ;wRpJW9f`%)on*q31K?YRZ?#{cb}BahvRi?*FFR<**%O@iWSw z9$kZw!6Z5hatgIN?9=E~P&haC%T zRdq|EM2q@C3j`8$(Vqiti>iI97(J){AX#9~nAl=3u%74(A?dyX9(9pK4im`JTmc!( zz$RLjoFA}6>>=wcW&_zbq^@3&xO{|Fdy4UCvYe;(2)RVaWmvI6k+3CFti!_7{;Gj76-PA;vdjztBX~OCY6gf8!sgGP_#`kHKwNlCNj9}klmrgkKiZi zSr3wE(htxN)$|?EKzrz6XLs_x&+mEOnf>+q;U|CtY-JF5NW-_wS{55v<;Zw=g_4H? ze1^^5)n(;OCgwyXiHa_(I!a93ZyFs}MHqh2y2X$x?|x-i?1=B85{iff?N|>)Ba{p? z?^UGCk&hS1Qm5{l=T4<7pJNr7x{0OeG8D?S3E@+tBb(;Xa^L*le!n9UQhRmXkDKyX zS=0OkRKHG){FhFaG|Pyds~ge0IuX4yo0nsqf%j~zFk+aisYssoyA2tS$`o>(@$c-1 z9G;IHR_v5>9J35=S11BZ1sPAovA__V>V|Gz2Lly`K_X=^XbTezWYE$)){nIwA-e)L+|w75d4-t7?x?Br8c|LSa6XaNwQCp zBib=ry@R{J?lH5+hDc4c>)=!^5@DH4SCGLfvRH%tRdRTZ8+taMSYL=`?Q@SvUku@# x|A1S&9pN*S@+B2*oH25XklPezhYa2lc9%Nd!AAv4)WhL? ()V' { + 0 4 + 3 4 + 5 4 + 9 5 + a 5 + d 6 + } + + method 'main ([Ljava/lang/String;)V' { + b 11 + c 15 + } +} + +Lines mapping: +14 <-> 5 +15 <-> 5 +16 <-> 5 +19 <-> 6 +20 <-> 6 +21 <-> 7 +37 <-> 12 +39 <-> 16 +Not mapped: +18 +28 +29 +30 +31 +33 diff --git a/testData/results/TestMissingConstructorCallGood.dec b/testData/results/TestMissingConstructorCallGood.dec new file mode 100644 index 0000000..43af112 --- /dev/null +++ b/testData/results/TestMissingConstructorCallGood.dec @@ -0,0 +1,60 @@ +package pkg; + +public class TestMissingConstructorCallGood { + private TestMissingConstructorCallGood(Object var1) { + }// 16 + + private TestMissingConstructorCallGood() { + System.out.println("Nobody will see what we do here!");// 22 23 24 + this((Object)null);// 27 28 + }// 29 + + public static void main(String... var0) { + try { + new TestMissingConstructorCallGood(); + } catch (Throwable var2) {// 45 + ; + } + + }// 47 +} + +class 'pkg/TestMissingConstructorCallGood' { + method ' (Ljava/lang/Object;)V' { + 4 4 + } + + method ' ()V' { + 0 7 + 3 7 + 5 7 + 9 8 + a 8 + d 9 + } + + method 'main ([Ljava/lang/String;)V' { + b 14 + c 18 + } +} + +Lines mapping: +16 <-> 5 +22 <-> 8 +23 <-> 8 +24 <-> 8 +27 <-> 9 +28 <-> 9 +29 <-> 10 +45 <-> 15 +47 <-> 19 +Not mapped: +14 +15 +26 +36 +37 +38 +39 +41 diff --git a/testData/src/pkg/TestMissingConstructorCallBad.jasm b/testData/src/pkg/TestMissingConstructorCallBad.jasm new file mode 100644 index 0000000..ff6f4b6 --- /dev/null +++ b/testData/src/pkg/TestMissingConstructorCallBad.jasm @@ -0,0 +1,42 @@ +/** + * This code can be assembled with asmtools + * using asmtools jasm -g *.jasm command line. + */ +package pkg; + +super public class TestMissingConstructorCallBad + version 52:0 +{ + +private Method "":"()V" + stack 2 locals 1 +{ + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + ldc String "Nobody will see what we do here!"; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + + aload_0; + aconst_null; + invokespecial Method "":"(Ljava/lang/Object;)V"; + return; +} + +public static varargs Method main:"([Ljava/lang/String;)V" + stack 2 locals 2 +{ + try t0; + new class TestMissingConstructorCallBad; + dup; + invokespecial Method "":"()V"; + pop; + endtry t0; + goto L12; + catch t0 java/lang/Throwable; + stack_frame_type stack1; + stack_map class java/lang/Throwable; + astore_1; + L12: stack_frame_type same; + return; +} + +} // end Class TestMissingConstructorCallBad diff --git a/testData/src/pkg/TestMissingConstructorCallGood.jasm b/testData/src/pkg/TestMissingConstructorCallGood.jasm new file mode 100644 index 0000000..b08ac87 --- /dev/null +++ b/testData/src/pkg/TestMissingConstructorCallGood.jasm @@ -0,0 +1,50 @@ +/** + * This code can be assembled with asmtools + * using asmtools jasm -g *.jasm command line. + */ +package pkg; + +super public class TestMissingConstructorCallGood + version 52:0 +{ + +private Method "":"(Ljava/lang/Object;)V" + stack 1 locals 2 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + +private Method "":"()V" + stack 2 locals 1 +{ + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + ldc String "Nobody will see what we do here!"; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + + aload_0; + aconst_null; + invokespecial Method "":"(Ljava/lang/Object;)V"; + return; +} + +public static varargs Method main:"([Ljava/lang/String;)V" + stack 2 locals 2 +{ + try t0; + new class TestMissingConstructorCallGood; + dup; + invokespecial Method "":"()V"; + pop; + endtry t0; + goto L12; + catch t0 java/lang/Throwable; + stack_frame_type stack1; + stack_map class java/lang/Throwable; + astore_1; + L12: stack_frame_type same; + return; +} + +} // end Class TestMissingConstructorCallGood