Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8351274

javac to null check immediately enclosing instance in inner class constructors

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P4 P4
    • 25
    • tools
    • None
    • behavioral
    • low
    • Hide
      There may be code using reflection or other JVM languages (raw bytecode) to exploit the lack of NPE when instantiating inner classes without enclosing instances. Such usages are out of spec of the JLS, and any evolution in these inner classes to start using the enclosing instances can cause NPE and break users.

      For compatibility, an undocumented flag is added to javac to avoid additional null checks on targets >=25.
      Show
      There may be code using reflection or other JVM languages (raw bytecode) to exploit the lack of NPE when instantiating inner classes without enclosing instances. Such usages are out of spec of the JLS, and any evolution in these inner classes to start using the enclosing instances can cause NPE and break users. For compatibility, an undocumented flag is added to javac to avoid additional null checks on targets >=25.
    • Class file construct, add/remove/modify command line option
    • Implementation

      Summary

      Currently, an inner class instance with null enclosing instances can be created by reflection, method handles, or direct bytecode invocation. javac's translation of inner class constructors will add a null check to the incoming immediately enclosing instance argument (unless this argument is delegated to another this() constructor call) to block such creations for target releases beginning in 25. This default behavior can be overridden with the undocumented nullCheckOuterThis flag like -XDnullCheckOuterThis=(true|false).

      Problem

      JLS provides that various use sites of inner class constructors should include null checks if the incoming immediately enclosing instance may be null, including for qualified instance creation expressions (JLS 15.9.4) and superconstructor invocations (JLS 8.8.7.1 "if the superclass constructor invocation is qualified"). Then, JLS assumes the enclosing instances are non-null in the usages in inner classes.

      However, JLS does not mandate any check in the declaration site of the inner class constructors. As a result, core reflection, method handles, or direct bytecode invocation may pass null for inner class constructors, and the usages of the enclosing instances later may see null and fail with an NPE.

      Solution

      Beginning in target release 25, javac will start emitting null checks in inner class constructors that calls a superclass constructor. Such constructors store to the synthetic field that captures the immediately enclosing instance. Other constructors all delegate to constructors that call superclass constructors.

      This is purely an implementation artifact with no JLS changes. In addition, these null checks will be emitted, even if the enclosing instance is unused and not stored into a field.

      These null checks will be emitted for target releases beginning in 25, and not emitted for earlier releases. Users can use the undocumented nullCheckOuterThis flag to override this default behavior, like -XDnullCheckOuterThis=(true|false).

      Note that the original javac-generated null checks for the JLS 15.9.4 and 8.8.7.1 provisions are kept as-is. They currently causes an NPE before other exceptions can arise, such as any run-time LinkageError or any error thrown by the inner class constructors (such as one that calls a super constructor with a static method that throws an unchecked exception), which the checks added by this solution do not cover.

      Specification

      No change.

      It seems the word "instance" in the JLS means the presence of an object, as in "class instance", as opposed to null references. Therefore, null-checking a parameter that must pass an instance makes sense.

            liach Chen Liang
            webbuggrp Webbug Group
            Vicente Arturo Romero Zaldivar
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: