Wed, 30 Apr 2014 23:29:43 +0100
8039026: Definitely unassigned field can be accessed
Reviewed-by: vromero, jlahoda
1.1 --- a/src/share/classes/com/sun/tools/javac/code/Source.java Wed Apr 30 23:26:43 2014 +0100 1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Source.java Wed Apr 30 23:29:43 2014 +0100 1.3 @@ -191,6 +191,9 @@ 1.4 public boolean allowObjectToPrimitiveCast() { 1.5 return compareTo(JDK1_7) >= 0; 1.6 } 1.7 + public boolean enforceThisDotInit() { 1.8 + return compareTo(JDK1_7) >= 0; 1.9 + } 1.10 public boolean allowPoly() { 1.11 return compareTo(JDK1_8) >= 0; 1.12 }
2.1 --- a/src/share/classes/com/sun/tools/javac/comp/Flow.java Wed Apr 30 23:26:43 2014 +0100 2.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Flow.java Wed Apr 30 23:29:43 2014 +0100 2.3 @@ -197,6 +197,7 @@ 2.4 private final boolean allowImprovedRethrowAnalysis; 2.5 private final boolean allowImprovedCatchAnalysis; 2.6 private final boolean allowEffectivelyFinalInInnerClasses; 2.7 + private final boolean enforceThisDotInit; 2.8 2.9 public static Flow instance(Context context) { 2.10 Flow instance = context.get(flowKey); 2.11 @@ -207,7 +208,7 @@ 2.12 2.13 public void analyzeTree(Env<AttrContext> env, TreeMaker make) { 2.14 new AliveAnalyzer().analyzeTree(env, make); 2.15 - new AssignAnalyzer(log, syms, lint, names).analyzeTree(env); 2.16 + new AssignAnalyzer(log, syms, lint, names, enforceThisDotInit).analyzeTree(env); 2.17 new FlowAnalyzer().analyzeTree(env, make); 2.18 new CaptureAnalyzer().analyzeTree(env, make); 2.19 } 2.20 @@ -239,7 +240,7 @@ 2.21 //related errors, which will allow for more errors to be detected 2.22 Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log); 2.23 try { 2.24 - new AssignAnalyzer(log, syms, lint, names).analyzeTree(env); 2.25 + new AssignAnalyzer(log, syms, lint, names, enforceThisDotInit).analyzeTree(env); 2.26 LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer(); 2.27 flowAnalyzer.analyzeTree(env, that, make); 2.28 return flowAnalyzer.inferredThrownTypes; 2.29 @@ -289,6 +290,7 @@ 2.30 allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis(); 2.31 allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis(); 2.32 allowEffectivelyFinalInInnerClasses = source.allowEffectivelyFinalInInnerClasses(); 2.33 + enforceThisDotInit = source.enforceThisDotInit(); 2.34 } 2.35 2.36 /** 2.37 @@ -1427,6 +1429,8 @@ 2.38 2.39 protected Names names; 2.40 2.41 + final boolean enforceThisDotInit; 2.42 + 2.43 public static class AbstractAssignPendingExit extends BaseAnalyzer.PendingExit { 2.44 2.45 final Bits inits; 2.46 @@ -1449,7 +1453,7 @@ 2.47 } 2.48 } 2.49 2.50 - public AbstractAssignAnalyzer(Bits inits, Symtab syms, Names names) { 2.51 + public AbstractAssignAnalyzer(Bits inits, Symtab syms, Names names, boolean enforceThisDotInit) { 2.52 this.inits = inits; 2.53 uninits = new Bits(); 2.54 uninitsTry = new Bits(); 2.55 @@ -1459,6 +1463,7 @@ 2.56 uninitsWhenFalse = new Bits(true); 2.57 this.syms = syms; 2.58 this.names = names; 2.59 + this.enforceThisDotInit = enforceThisDotInit; 2.60 } 2.61 2.62 private boolean isInitialConstructor = false; 2.63 @@ -2280,12 +2285,34 @@ 2.64 2.65 public void visitAssign(JCAssign tree) { 2.66 JCTree lhs = TreeInfo.skipParens(tree.lhs); 2.67 - if (!(lhs instanceof JCIdent)) { 2.68 + if (!isIdentOrThisDotIdent(lhs)) 2.69 scanExpr(lhs); 2.70 - } 2.71 scanExpr(tree.rhs); 2.72 letInit(lhs); 2.73 } 2.74 + private boolean isIdentOrThisDotIdent(JCTree lhs) { 2.75 + if (lhs.hasTag(IDENT)) 2.76 + return true; 2.77 + if (!lhs.hasTag(SELECT)) 2.78 + return false; 2.79 + 2.80 + JCFieldAccess fa = (JCFieldAccess)lhs; 2.81 + return fa.selected.hasTag(IDENT) && 2.82 + ((JCIdent)fa.selected).name == names._this; 2.83 + } 2.84 + 2.85 + // check fields accessed through this.<field> are definitely 2.86 + // assigned before reading their value 2.87 + public void visitSelect(JCFieldAccess tree) { 2.88 + super.visitSelect(tree); 2.89 + if (enforceThisDotInit && 2.90 + tree.selected.hasTag(IDENT) && 2.91 + ((JCIdent)tree.selected).name == names._this && 2.92 + tree.sym.kind == VAR) 2.93 + { 2.94 + checkInit(tree.pos(), (VarSymbol)tree.sym); 2.95 + } 2.96 + } 2.97 2.98 public void visitAssignop(JCAssignOp tree) { 2.99 scanExpr(tree.lhs); 2.100 @@ -2419,8 +2446,8 @@ 2.101 } 2.102 } 2.103 2.104 - public AssignAnalyzer(Log log, Symtab syms, Lint lint, Names names) { 2.105 - super(new Bits(), syms, names); 2.106 + public AssignAnalyzer(Log log, Symtab syms, Lint lint, Names names, boolean enforceThisDotInit) { 2.107 + super(new Bits(), syms, names, enforceThisDotInit); 2.108 this.log = log; 2.109 this.lint = lint; 2.110 }
3.1 --- a/src/share/classes/com/sun/tools/javac/jvm/Gen.java Wed Apr 30 23:26:43 2014 +0100 3.2 +++ b/src/share/classes/com/sun/tools/javac/jvm/Gen.java Wed Apr 30 23:29:43 2014 +0100 3.3 @@ -1,5 +1,5 @@ 3.4 /* 3.5 - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. 3.6 + * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. 3.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3.8 * 3.9 * This code is free software; you can redistribute it and/or modify it 3.10 @@ -2818,7 +2818,7 @@ 3.11 } 3.12 3.13 private LVTAssignAnalyzer(LVTRanges lvtRanges, Symtab syms, Names names) { 3.14 - super(new LVTBits(), syms, names); 3.15 + super(new LVTBits(), syms, names, false); 3.16 lvtInits = (LVTBits)inits; 3.17 this.lvtRanges = lvtRanges; 3.18 }
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/test/tools/javac/DefiniteAssignment/T8039026.java Wed Apr 30 23:29:43 2014 +0100 4.3 @@ -0,0 +1,21 @@ 4.4 +/* 4.5 + * @test /nodynamiccopyright/ 4.6 + * @bug 8039026 4.7 + * @summary Definitely unassigned field can be accessed 4.8 + * @compile/fail/ref=T8039026.out -XDrawDiagnostics T8039026.java 4.9 + */ 4.10 + 4.11 +public class T8039026 { 4.12 + final int x,y,z; 4.13 + final int a = this.y; // <- error 4.14 + { 4.15 + int b = true ? this.x : 0; // <- error 4.16 + System.out.println(this.x); // <- error 4.17 + this.y = 1; 4.18 + } 4.19 + T8039026() { 4.20 + this.x = 1; // <- no error! 4.21 + this.y = 1; // <- error 4.22 + this.z = this.x; // <- no error 4.23 + } 4.24 +}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/test/tools/javac/DefiniteAssignment/T8039026.out Wed Apr 30 23:29:43 2014 +0100 5.3 @@ -0,0 +1,4 @@ 5.4 +T8039026.java:10:23: compiler.err.var.might.not.have.been.initialized: y 5.5 +T8039026.java:12:28: compiler.err.var.might.not.have.been.initialized: x 5.6 +T8039026.java:18:13: compiler.err.var.might.already.be.assigned: y 5.7 +3 errors