8168480: Speculative attribution of lambda causes NPE in Flow
Summary: Flow attempts to analyze too much of a lambda body during attribution
Reviewed-by: vromero
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java Sat Oct 22 12:27:52 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java Mon Oct 24 14:47:48 2016 +0100
@@ -29,6 +29,7 @@
import java.util.HashMap;
+import com.sun.source.tree.LambdaExpressionTree.BodyKind;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Scope.WriteableScope;
import com.sun.tools.javac.tree.*;
@@ -224,7 +225,7 @@
diagHandler = new Log.DiscardDiagnosticHandler(log);
}
try {
- new AliveAnalyzer().analyzeTree(env, that, make);
+ new LambdaAliveAnalyzer().analyzeTree(env, that, make);
} finally {
if (!speculative) {
log.popDiagnosticHandler(diagHandler);
@@ -241,19 +242,7 @@
//related errors, which will allow for more errors to be detected
Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
try {
- new AssignAnalyzer() {
- WriteableScope enclosedSymbols = WriteableScope.create(env.enclClass.sym);
- @Override
- public void visitVarDef(JCVariableDecl tree) {
- enclosedSymbols.enter(tree.sym);
- super.visitVarDef(tree);
- }
- @Override
- protected boolean trackable(VarSymbol sym) {
- return enclosedSymbols.includes(sym) &&
- sym.owner.kind == MTH;
- }
- }.analyzeTree(env, that);
+ new LambdaAssignAnalyzer(env).analyzeTree(env, that);
LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
flowAnalyzer.analyzeTree(env, that, make);
return flowAnalyzer.inferredThrownTypes;
@@ -1341,6 +1330,79 @@
}
/**
+ * Specialized pass that performs reachability analysis on a lambda
+ */
+ class LambdaAliveAnalyzer extends AliveAnalyzer {
+
+ boolean inLambda;
+
+ @Override
+ public void visitReturn(JCReturn tree) {
+ //ignore lambda return expression (which might not even be attributed)
+ recordExit(new PendingExit(tree));
+ }
+
+ @Override
+ public void visitLambda(JCLambda tree) {
+ if (inLambda || tree.getBodyKind() == BodyKind.EXPRESSION) {
+ return;
+ }
+ inLambda = true;
+ try {
+ super.visitLambda(tree);
+ } finally {
+ inLambda = false;
+ }
+ }
+
+ @Override
+ public void visitClassDef(JCClassDecl tree) {
+ //skip
+ }
+ }
+
+ /**
+ * Specialized pass that performs DA/DU on a lambda
+ */
+ class LambdaAssignAnalyzer extends AssignAnalyzer {
+ WriteableScope enclosedSymbols;
+ boolean inLambda;
+
+ LambdaAssignAnalyzer(Env<AttrContext> env) {
+ enclosedSymbols = WriteableScope.create(env.enclClass.sym);
+ }
+
+ @Override
+ public void visitLambda(JCLambda tree) {
+ if (inLambda) {
+ return;
+ }
+ inLambda = true;
+ try {
+ super.visitLambda(tree);
+ } finally {
+ inLambda = false;
+ }
+ }
+
+ @Override
+ public void visitVarDef(JCVariableDecl tree) {
+ enclosedSymbols.enter(tree.sym);
+ super.visitVarDef(tree);
+ }
+ @Override
+ protected boolean trackable(VarSymbol sym) {
+ return enclosedSymbols.includes(sym) &&
+ sym.owner.kind == MTH;
+ }
+
+ @Override
+ public void visitClassDef(JCClassDecl tree) {
+ //skip
+ }
+ }
+
+ /**
* Specialized pass that performs inference of thrown types for lambdas.
*/
class LambdaFlowAnalyzer extends FlowAnalyzer {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8168480/T8168480.java Mon Oct 24 14:47:48 2016 +0100
@@ -0,0 +1,125 @@
+/*
+ * @test
+ * @bug 8168480
+ * @summary Speculative attribution of lambda causes NPE in Flow
+ * @compile T8168480.java
+ */
+
+import java.util.function.Supplier;
+
+class T8168480 {
+ void f(Runnable r) { }
+ void s(Supplier<Runnable> r) { }
+
+ private void testVoid(boolean cond) {
+ f(() ->
+ new Runnable() {
+ public void run() {
+ switch (42) {
+ default:
+ break;
+ }
+ }
+ }.run());
+
+ f(() ->
+ f(() -> {
+ switch (42) {
+ default:
+ break;
+ }
+ }));
+
+ f(() -> {
+ if (cond) {
+ new Runnable() {
+ public void run() {
+ switch (42) {
+ default:
+ break;
+ }
+ }
+ }.run();
+ } else {
+ f(() -> {
+ switch (42) {
+ default:
+ break;
+ }
+ });
+ }
+ });
+ }
+
+ private void testReturn(boolean cond) {
+ s(() ->
+ new Runnable() {
+ public void run() {
+ switch (42) {
+ default:
+ break;
+ }
+ }
+ });
+
+ s(() ->
+ () -> {
+ switch (42) {
+ default:
+ break;
+ }
+ });
+
+ s(() -> {
+ if (cond) {
+ return new Runnable() {
+ public void run() {
+ switch (42) {
+ default:
+ break;
+ }
+ }
+ };
+ } else {
+ return () -> {
+ switch (42) {
+ default:
+ break;
+ }
+ };
+ }
+ });
+
+ s(() -> {
+ return cond ?
+ new Runnable() {
+ public void run() {
+ switch (42) {
+ default:
+ break;
+ }
+ }
+ } : () -> {
+ switch (42) {
+ default:
+ break;
+ }
+ };
+ });
+
+ s(() -> cond ?
+ new Runnable() {
+ public void run() {
+ switch (42) {
+ default:
+ break;
+ }
+ }
+ } : () -> {
+ switch (42) {
+ default:
+ break;
+ }
+ });
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8168480/T8168480b.java Mon Oct 24 14:47:48 2016 +0100
@@ -0,0 +1,12 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8168480
+ * @summary Speculative attribution of lambda causes NPE in Flow
+ * @compile/fail/ref=T8168480b.out -XDrawDiagnostics T8168480b.java
+ */
+
+import java.util.function.Supplier;
+
+class T8168480b {
+ Supplier<Runnable> ssr = () -> () -> { while (true); System.err.println("Hello"); };
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8168480/T8168480b.out Mon Oct 24 14:47:48 2016 +0100
@@ -0,0 +1,2 @@
+T8168480b.java:11:57: compiler.err.unreachable.stmt
+1 error