8039026: Definitely unassigned field can be accessed

Wed, 30 Apr 2014 23:29:43 +0100

author
pgovereau
date
Wed, 30 Apr 2014 23:29:43 +0100
changeset 2376
12f99d1f23d9
parent 2375
3a2ebbad5911
child 2377
b5c2375893e2

8039026: Definitely unassigned field can be accessed
Reviewed-by: vromero, jlahoda

src/share/classes/com/sun/tools/javac/code/Source.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/comp/Flow.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/jvm/Gen.java file | annotate | diff | comparison | revisions
test/tools/javac/DefiniteAssignment/T8039026.java file | annotate | diff | comparison | revisions
test/tools/javac/DefiniteAssignment/T8039026.out file | annotate | diff | comparison | revisions
     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

mercurial