JDK-8292175 : Optimization for ternary conditional operator with boxing cause NPE
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 11
  • Priority: P4
  • Status: Closed
  • Resolution: Not an Issue
  • OS: generic
  • CPU: generic
  • Submitted: 2022-08-02
  • Updated: 2025-06-20
  • Resolved: 2022-08-19
Related Reports
Duplicate :  
Description
ADDITIONAL SYSTEM INFORMATION :
OS: windows 11 and CentOS 7
Java 11.0.12

A DESCRIPTION OF THE PROBLEM :
When using following ternary conditional operator will throw NPE:

    public static void main(String[] args) {
        BigDecimal a = null;
        BigDecimal b = null;
        Double x = a!=null ?
                a.doubleValue() : (
                    b!=null ?
                    b.doubleValue() :
                    null
                );
        System.out.print(x);
    }

the byte generated byte code as following:
  public static void main(java.lang.String[]);
    Code:
       0: aconst_null
       1: astore_1
       2: aconst_null
       3: astore_2
       4: aload_1
       5: ifnull        15
       8: aload_1
       9: invokevirtual #2                  // Method java/math/BigDecimal.doubleValue:()D
      12: goto          33
      15: aload_2
      16: ifnull        29
      19: aload_2
      20: invokevirtual #2                  // Method java/math/BigDecimal.doubleValue:()D
      23: invokestatic  #3                  // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
      26: goto          30
      29: aconst_null
      30: invokevirtual #4                  // Method java/lang/Double.doubleValue:()D
      33: invokestatic  #3                  // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
      36: astore_3
      37: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      40: aload_3
      41: invokevirtual #6                  // Method java/io/PrintStream.print:(Ljava/lang/Object;)V
      44: return

as above, see label 30 and 34: hotspot optimize the second ternary conditional operator with type inference assume it was a Double and invoked boxing / unboxing that caused NPE.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
    public static void main(String[] args) {
        BigDecimal a = null;
        BigDecimal b = null;
        Double x = a!=null ?
                a.doubleValue() : (
                    b!=null ?
                    b.doubleValue() :
                    null
                );
        System.out.print(x);
    }

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
print null
ACTUAL -
NullPointException raised

---------- BEGIN SOURCE ----------
    public static void main(String[] args) {
        BigDecimal a = null;
        BigDecimal b = null;
        Double x = a!=null ?
                a.doubleValue() : (
                    b!=null ?
                    b.doubleValue() :
                    null
                );
        System.out.print(x);
    }
---------- END SOURCE ----------

FREQUENCY : always



Comments
This is not an issue. Example: int a = -1; Integer b = null; Integer result = a > 0 ? a : b; The second arg. of ternary operator is of type int and the third arg is of type Integer. The compiler then decides that the type of the whole expression will be plain int and tries to unbox b which is actually null. Hence NPE is thrown. It is because of the unboxing NPE is thrown. This is similar case here.
19-08-2022

This does not seem to be a HotSpot compiler bug (can be reproduced in interpreter-only mode). Passing on to javac team for further analysis, feel free to send it back if my judgement was wrong.
10-08-2022