Skip to content

Commit a5e03e2

Browse files
committedJun 10, 2020
8235564: javac crashes while compiling incorrect method invocation with member reference
Reviewed-by: vromero
1 parent 0e770d1 commit a5e03e2

File tree

4 files changed

+225
-4
lines changed

4 files changed

+225
-4
lines changed
 

‎src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskPool.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
2626
package com.sun.tools.javac.api;
2727

2828
import java.io.PrintStream;
29+
import java.io.PrintWriter;
2930
import java.io.Writer;
3031
import java.util.ArrayDeque;
3132
import java.util.ArrayList;
@@ -184,6 +185,10 @@ public <Z> Z getTask(Writer out,
184185

185186
task.addTaskListener(ctx);
186187

188+
if (out != null) {
189+
Log.instance(ctx).setWriters(new PrintWriter(out, true));
190+
}
191+
187192
Z result = worker.withTask(task);
188193

189194
//not returning the context to the pool if task crashes with an exception

‎src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -1082,7 +1082,12 @@ public Type visitMethodType(Type.MethodType t, Type pt) {
10821082
* a default expected type (j.l.Object).
10831083
*/
10841084
private Type recover(DeferredType dt, Type pt) {
1085-
dt.check(attr.new RecoveryInfo(deferredAttrContext, pt != null ? pt : Type.recoveryType) {
1085+
boolean isLambdaOrMemberRef =
1086+
dt.tree.hasTag(REFERENCE) || dt.tree.hasTag(LAMBDA);
1087+
boolean needsRecoveryType =
1088+
pt == null || (isLambdaOrMemberRef && !types.isFunctionalInterface(pt));
1089+
Type ptRecovery = needsRecoveryType ? Type.recoveryType: pt;
1090+
dt.check(attr.new RecoveryInfo(deferredAttrContext, ptRecovery) {
10861091
@Override
10871092
protected Type check(DiagnosticPosition pos, Type found) {
10881093
return chk.checkNonVoid(pos, super.check(pos, found));

‎test/langtools/tools/javac/api/TestGetScopeResult.java

+29-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -157,6 +157,34 @@ public void run() throws IOException {
157157

158158
doTest("class Test { void test() { cand((t, var s) -> \"\"); } void cand(I i) { } interface I { public String test(String s); } }",
159159
implicitExplicitConflict2);
160+
161+
String[] noFunctionInterface = {
162+
"s:none",
163+
":t",
164+
"super:java.lang.Object",
165+
"this:Test"
166+
};
167+
168+
doTest("class Test { void test() { cand((t, var s) -> \"\"); } void cand(String s) { } }",
169+
noFunctionInterface);
170+
171+
String[] invocationInMethodInvocation = {
172+
"d2:java.lang.Double",
173+
"d1:java.lang.Double",
174+
"super:java.lang.Object",
175+
"this:Test"
176+
};
177+
178+
doTest("""
179+
class Test {
180+
void test() { test(reduce(0.0, (d1, d2) -> 0)); }
181+
void test(int i) {}
182+
<T> T reduce(T t, BiFunction<T, T, T> f1) {}
183+
static interface BiFunction<R, P, Q> {
184+
R apply(P p, Q q);
185+
}
186+
}""",
187+
invocationInMethodInvocation);
160188
}
161189

162190
public void doTest(String code, String... expected) throws IOException {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
/*
2+
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8235564
27+
* @summary Verify that passing member references to a method not accepting
28+
* functional interface does not crash the compiler.
29+
* @library /tools/lib /tools/javac/lib
30+
* @modules jdk.compiler/com.sun.tools.javac.api
31+
* jdk.compiler/com.sun.tools.javac.file
32+
* jdk.compiler/com.sun.tools.javac.main
33+
* jdk.compiler/com.sun.tools.javac.util
34+
* @build toolbox.ToolBox toolbox.JavacTask
35+
* @build combo.ComboTestHelper
36+
* @compile T8235564.java
37+
* @run main T8235564
38+
*/
39+
40+
import combo.ComboInstance;
41+
import combo.ComboParameter;
42+
import combo.ComboTask;
43+
import combo.ComboTestHelper;
44+
import java.io.StringWriter;
45+
import java.util.ArrayList;
46+
import java.util.List;
47+
import java.util.stream.Collectors;
48+
import javax.tools.Diagnostic;
49+
import toolbox.ToolBox;
50+
51+
public class T8235564 extends ComboInstance<T8235564> {
52+
protected ToolBox tb;
53+
54+
T8235564() {
55+
super();
56+
tb = new ToolBox();
57+
}
58+
59+
public static void main(String... args) throws Exception {
60+
new ComboTestHelper<T8235564>()
61+
.withDimension("INVOCATION", (x, invocation) -> x.invocation = invocation, Invocation.values())
62+
.withDimension("PARAM", (x, param) -> x.param = param, Parameter.values())
63+
.run(T8235564::new);
64+
}
65+
66+
private Invocation invocation;
67+
private Parameter param;
68+
69+
private static final String MAIN_TEMPLATE =
70+
"""
71+
public class Test {
72+
static void test() {
73+
Runnable r = () -> {};
74+
#{INVOCATION};
75+
}
76+
private static void existingWithFunctional(Runnable r) {}
77+
private static void existingWithoutFunctional(String parameter) {}
78+
}
79+
""";
80+
81+
@Override
82+
protected void doWork() throws Throwable {
83+
StringWriter out = new StringWriter();
84+
85+
ComboTask task = newCompilationTask()
86+
.withSourceFromTemplate(MAIN_TEMPLATE, pname -> switch (pname) {
87+
case "INVOCATION" -> invocation;
88+
case "PARAM" -> param;
89+
default -> throw new UnsupportedOperationException(pname);
90+
})
91+
.withOption("-XDshould-stop.at=FLOW")
92+
.withOption("-XDrawDiagnostics")
93+
.withOption("-XDdev")
94+
.withWriter(out);
95+
96+
task.analyze(result -> {
97+
List<String> diags = result.diagnosticsForKind(Diagnostic.Kind.ERROR)
98+
.stream()
99+
.map(d -> d.getLineNumber() + ":" + d.getCode())
100+
.collect(Collectors.toList());
101+
List<String> expected = new ArrayList<>();
102+
switch (param) {
103+
case VALID_VARIABLE, VALID_LAMBDA, VALID_MEMBER_REF -> {}
104+
case UNDEFINED_VARIABLE ->
105+
expected.add("4:compiler.err.cant.resolve.location");
106+
case UNDEFINED_METHOD, UNDEFINED_LAMBDA ->
107+
expected.add("4:compiler.err.cant.resolve.location.args");
108+
case UNDEFINED_MEMBER_REF ->
109+
expected.add("4:compiler.err.invalid.mref");
110+
case UNDEFINED_CONDEXPR -> {
111+
if (invocation != Invocation.EXISTING_WITHOUT_FUNCTIONAL) {
112+
expected.add("4:compiler.err.invalid.mref");
113+
expected.add("4:compiler.err.invalid.mref");
114+
}
115+
}
116+
}
117+
switch (invocation) {
118+
case EXISTING_WITH_FUNCTIONAL -> {
119+
if (param == Parameter.UNDEFINED_CONDEXPR) {
120+
expected.add("4:compiler.err.cant.apply.symbol");
121+
}
122+
}
123+
case EXISTING_WITHOUT_FUNCTIONAL -> {
124+
if (param != Parameter.UNDEFINED_VARIABLE &&
125+
param != Parameter.UNDEFINED_MEMBER_REF &&
126+
param != Parameter.UNDEFINED_METHOD) {
127+
expected.add("4:compiler.err.cant.apply.symbol");
128+
}
129+
}
130+
case UNDEFINED -> {
131+
if (param != Parameter.UNDEFINED_VARIABLE &&
132+
param != Parameter.UNDEFINED_MEMBER_REF &&
133+
param != Parameter.UNDEFINED_METHOD) {
134+
expected.add("4:compiler.err.cant.resolve.location.args");
135+
}
136+
}
137+
}
138+
if (!expected.equals(diags)) {
139+
throw new AssertionError("Expected errors not found, expected: " + expected + ", actual: " + diags);
140+
}
141+
if (out.toString().length() > 0) {
142+
throw new AssertionError("No output expected, but got:\n" + out + "\n\n" + result.compilationInfo());
143+
}
144+
});
145+
}
146+
147+
public enum Invocation implements ComboParameter {
148+
EXISTING_WITH_FUNCTIONAL("existingWithFunctional(#{PARAM})"),
149+
EXISTING_WITHOUT_FUNCTIONAL("existingWithoutFunctional(#{PARAM})"),
150+
UNDEFINED("undefined(#{PARAM})");
151+
private final String invocation;
152+
153+
private Invocation(String invocation) {
154+
this.invocation = invocation;
155+
}
156+
157+
@Override
158+
public String expand(String optParameter) {
159+
return invocation;
160+
}
161+
}
162+
163+
public enum Parameter implements ComboParameter {
164+
VALID_VARIABLE("r"),
165+
VALID_LAMBDA("() -> {}"),
166+
VALID_MEMBER_REF("Test::test"),
167+
UNDEFINED_VARIABLE("undefined"),
168+
UNDEFINED_LAMBDA("() -> {undefined();}"),
169+
UNDEFINED_MEMBER_REF("Test::undefined"),
170+
UNDEFINED_METHOD("undefined()"),
171+
UNDEFINED_CONDEXPR("1 == 2 ? Test::undefined : Test::undefined");
172+
private final String code;
173+
174+
private Parameter(String code) {
175+
this.code = code;
176+
}
177+
178+
@Override
179+
public String expand(String optParameter) {
180+
return code;
181+
}
182+
}
183+
}

0 commit comments

Comments
 (0)
Please sign in to comment.