JDK-8322882 : Null pointer error when compiling Static initializer in a local class
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 21
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2023-12-28
  • Updated: 2025-11-18
  • Resolved: 2024-11-15
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 24
24 b25Fixed
Related Reports
Duplicate :  
Duplicate :  
Description
ADDITIONAL SYSTEM INFORMATION :
System: Ubuntu 22.04, Linux kernel version 6.2.0-39-generic
Javac: javac 21.0.1

A DESCRIPTION OF THE PROBLEM :
When compiling a class which has two local classes (A and B), A captures a variable, B reference A in a static initializer, javac will throw null pointer error.

This is an example:

public class TestUseTree2 {
    public static void main(String[] args) {
        String i = "111";
        class TestUseTree2_ROOT {
            // ctor arg i
            void f() {
                System.out.println(i);
            }
        }

        class TestUseTree2_ROOT1 {
            // clinit args: i?
            // should be prohibited, use `new TestUseTree2_ROOT()` is a static context
            static TestUseTree2_ROOT r = new TestUseTree2_ROOT();
        }

        TestUseTree2_ROOT1.r.f();
    }
}

And javac will throw a null pointer error.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Create a java source file, named "TestUseTree.java", with such content:

```
public class TestUseTree2 {
    public static void main(String[] args) {
        String i = "111";
        class TestUseTree2_ROOT {
            // ctor arg i
            void f() {
                System.out.println(i);
            }
        }

        class TestUseTree2_ROOT1 {
            // clinit args: i?
            // should be prohibited, use `new TestUseTree2_ROOT()` is a static context
            static TestUseTree2_ROOT r = new TestUseTree2_ROOT();
        }

        TestUseTree2_ROOT1.r.f();
    }
}
```

2. Compile with javac, command: `javac TestUseTree.java`

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Javac will report error for `static TestUseTree2_ROOT r = new TestUseTree2_ROOT();`, because TestUseTree2_Root cannot be accessed from a static context.
ACTUAL -
Javac throws a null pointer error:

```
An exception has occurred in the compiler (21.0.1). Please file a bug against the Java compiler via the Java bug reporting page (https://bugreport.java.com) after checking the Bug Database (https://bugs.java.com) for duplicates. Include your program, the following diagnostic, and the parameters passed to the Java compiler in your report. Thank you.
java.lang.NullPointerException: Cannot read field "sym" because "this.lvar[0]" is null
        at jdk.compiler/com.sun.tools.javac.jvm.Code.emitop0(Code.java:568)
        at jdk.compiler/com.sun.tools.javac.jvm.Items$SelfItem.load(Items.java:369)
        at jdk.compiler/com.sun.tools.javac.jvm.Gen.visitIdent(Gen.java:2334)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCIdent.accept(JCTree.java:2715)
        at jdk.compiler/com.sun.tools.javac.jvm.Gen.genExpr(Gen.java:885)
        at jdk.compiler/com.sun.tools.javac.jvm.Gen.genArgs(Gen.java:910)
        at jdk.compiler/com.sun.tools.javac.jvm.Gen.visitNewClass(Gen.java:2019)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCNewClass.accept(JCTree.java:1871)
        at jdk.compiler/com.sun.tools.javac.jvm.Gen.genExpr(Gen.java:885)
        at jdk.compiler/com.sun.tools.javac.jvm.Gen.visitAssign(Gen.java:2075)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCAssign.accept(JCTree.java:2060)
        at jdk.compiler/com.sun.tools.javac.jvm.Gen.genExpr(Gen.java:885)
        at jdk.compiler/com.sun.tools.javac.jvm.Gen.visitExec(Gen.java:1794)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCExpressionStatement.accept(JCTree.java:1603)
        at jdk.compiler/com.sun.tools.javac.jvm.Gen.genDef(Gen.java:614)
        at jdk.compiler/com.sun.tools.javac.jvm.Gen.genStat(Gen.java:649)
        at jdk.compiler/com.sun.tools.javac.jvm.Gen.genStat(Gen.java:635)
        at jdk.compiler/com.sun.tools.javac.jvm.Gen.genStats(Gen.java:686)
        at jdk.compiler/com.sun.tools.javac.jvm.Gen.doVisitBlock(Gen.java:1128)
        at jdk.compiler/com.sun.tools.javac.jvm.Gen.visitBlock(Gen.java:1121)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:1092)
        at jdk.compiler/com.sun.tools.javac.jvm.Gen.genDef(Gen.java:614)
        at jdk.compiler/com.sun.tools.javac.jvm.Gen.genStat(Gen.java:649)
        at jdk.compiler/com.sun.tools.javac.jvm.Gen.genMethod(Gen.java:975)
        at jdk.compiler/com.sun.tools.javac.jvm.Gen.visitMethodDef(Gen.java:938)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:916)
        at jdk.compiler/com.sun.tools.javac.jvm.Gen.genDef(Gen.java:614)
        at jdk.compiler/com.sun.tools.javac.jvm.Gen.genClass(Gen.java:2472)
        at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.genCode(JavaCompiler.java:769)
        at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.generate(JavaCompiler.java:1710)
        at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.generate(JavaCompiler.java:1678)
        at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:976)
        at jdk.compiler/com.sun.tools.javac.main.Main.compile(Main.java:319)
        at jdk.compiler/com.sun.tools.javac.main.Main.compile(Main.java:178)
        at jdk.compiler/com.sun.tools.javac.Main.compile(Main.java:64)
        at jdk.compiler/com.sun.tools.javac.Main.main(Main.java:50)
printing javac parameters to: /home/ayanamists/repo/handscript/constructor/javac.20231228_150905.args
```

---------- BEGIN SOURCE ----------
public class TestUseTree2 {
    public static void main(String[] args) {
        String i = "111";
        class TestUseTree2_ROOT {
            // ctor arg i
            void f() {
                System.out.println(i);
            }
        }

        class TestUseTree2_ROOT1 {
            // clinit args: i?
            // should be prohibited, use `new TestUseTree2_ROOT()` is a static context
            static TestUseTree2_ROOT r = new TestUseTree2_ROOT();
        }

        TestUseTree2_ROOT1.r.f();
    }
}
---------- END SOURCE ----------

FREQUENCY : always



Comments
Changeset: 5b9932f8 Branch: master Author: Maurizio Cimadamore <mcimadamore@openjdk.org> Date: 2024-11-15 10:07:18 +0000 URL: https://git.openjdk.org/jdk/commit/5b9932f8f3c320f1d2c95403478a6069d05da52a
15-11-2024

A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk/pull/21410 Date: 2024-10-08 14:42:19 +0000
08-10-2024

A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk/pull/19904 Date: 2024-06-26 11:17:50 +0000
09-07-2024

A pull request was submitted for review. URL: https://git.openjdk.org/jdk/pull/19754 Date: 2024-06-17 17:23:03 +0000
17-06-2024

Talking to my self... local classes can have static members since JDK 16 and JDK-8254321. So the program is still illegal but it should gracefully fail to compile with some error that looks like this: Test.java:4: error: non-static variable args cannot be referenced from a static context { args.hashCode(); } ^ Although "non-static variable args" is something of a misnomer.
14-06-2024

Even simpler test case: public class Test { public static void main(String[] args) { class Local { { args.hashCode(); } static { new Local(); } } } } Just realized that local classes can't have static members (right?) and if so the program is illegal.
14-06-2024

Slightly simpler test case: public class StaticNewInnerTest { public static void main(String[] args) { class Local1 { { System.out.println(args); } } class Local2 { static Local1 x = new Local1(); } } } Stating the semi-obvious, the problem here is that the compiler doesn't seem to ever verify that any captured free variables required by the local class' constructor are available at the point of construction.
14-06-2024