8168480: Speculative attribution of lambda causes NPE in Flow

Flow attempts to analyze too much of a lambda body during attribution

Reviewed-by: vromero
This commit is contained in:
Maurizio Cimadamore 2016-10-24 14:47:48 +01:00
parent 5078ccdb18
commit d072e7faa4
4 changed files with 215 additions and 14 deletions

View File

@ -29,6 +29,7 @@ package com.sun.tools.javac.comp;
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 @@ public class Flow {
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 @@ public class Flow {
//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;
@ -1340,6 +1329,79 @@ public class Flow {
}
}
/**
* 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.
*/

View File

@ -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;
}
});
}
}

View File

@ -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"); };
}

View File

@ -0,0 +1,2 @@
T8168480b.java:11:57: compiler.err.unreachable.stmt
1 error