JDK-8356989 : NPE in OpenJDK 21 when calling List.getLast() after addFirst() in loop
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 21.0.7
  • Priority: P4
  • Status: New
  • Resolution: Unresolved
  • OS: generic
  • CPU: generic
  • Submitted: 2025-05-09
  • Updated: 2025-05-14
Description
ADDITIONAL SYSTEM INFORMATION :
macOS version:

```java
Software:

    System Software Overview:

      System Version: macOS 13.2 (22D49)
      Kernel Version: Darwin 22.3.0
      Boot Volume: Macintosh HD
      Boot Mode: Normal
      Computer Name: MacBook Pro
      User Name: MacBook
      Secure Virtual Memory: Enabled
      System Integrity Protection: Enabled
      Time since boot: 1 day, 2 hours, 19 minutes

Hardware:

    Hardware Overview:

      Model Name: MacBook Pro
      Model Identifier: MacBookPro18,1
      Model Number: MK193CH/A
      Chip: Apple M1 Pro
      Total Number of Cores: 10 (8 performance and 2 efficiency)
      Memory: 16 GB
      System Firmware Version: 8419.80.7
      OS Loader Version: 8419.80.7
      Activation Lock Status: Disabled
```

OpenJDK version:

```jsx
openjdk version "21.0.7" 2025-04-15 LTS
OpenJDK Runtime Environment Temurin-21.0.7+6 (build 21.0.7+6-LTS)
OpenJDK 64-Bit Server VM Temurin-21.0.7+6 (build 21.0.7+6-LTS, mixed mode, sharing)
```

A DESCRIPTION OF THE PROBLEM :
### Description:

The provided test case triggers a `java.lang.NullPointerException` when executed on **OpenJDK 21**, while the same code does not exhibit this behavior on alternative JVM implementations, such as OpenJ9. Interestingly, the exception disappears if any other line in the test program is removed, suggesting that this issue may be related to JIT compiler optimizations.

```java
public class Test {

    public static int[] arr = new int[500];
    public static void main(String[] args) {
        try {
            int a = 7, b = 14;
            for (int i = 16; i < 338; ++i) {
                for (long l = 4; l < 78; ++l) {
                    Double.doubleToLongBits(checkSum(new double[400]));
                    java.util.List<java.lang.String> sequencedList = new java.util.ArrayList<>(java.util.List.of("A", "B", "C"));
                    sequencedList.addFirst("Z");
                    sequencedList.getLast().length();
                }
                try {
                    a = (a % Test.arr[i]);
                } catch (ArithmeticException a_e) {
                }
                b = 123;
                do {
                } while (b-- > 0);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static double checkSum(double[] a) {
        double sum = 0;
        for (int j = 0; j < a.length; j++) {
            sum += (a[j] / (j + 1) + a[j] % (j + 1));
        }
        return sum;
    }
}
```

### Observed Behavior:

When executing the program using **OpenJDK 21**, the following exception is thrown:

```
java.lang.NullPointerException: Cannot invoke "String.length()" because the return value of "java.util.List.getLast()" is null
        at Test.main(Test.java:12)
```

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Compile the `Test.java` file using `javac`.
2. Run the `Test` class  using OpenJDK 21.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The program should execute normally and terminate without throwing any exceptions.
ACTUAL -
The program throws a NullPointerException due to an unexpected null return from List.getLast(), which should not occur under normal conditions.

---------- BEGIN SOURCE ----------
public class Test {

    public static int[] arr = new int[500];
    public static void main(String[] args) {
        try {
            int a = 7, b = 14;
            for (int i = 16; i < 338; ++i) {
                for (long l = 4; l < 78; ++l) {
                    Double.doubleToLongBits(checkSum(new double[400]));
                    java.util.List<java.lang.String> sequencedList = new java.util.ArrayList<>(java.util.List.of("A", "B", "C"));
                    sequencedList.addFirst("Z");
                    sequencedList.getLast().length();
                }
                try {
                    a = (a % Test.arr[i]);
                } catch (ArithmeticException a_e) {
                }
                b = 123;
                do {
                } while (b-- > 0);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static double checkSum(double[] a) {
        double sum = 0;
        for (int j = 0; j < a.length; j++) {
            sum += (a[j] / (j + 1) + a[j] % (j + 1));
        }
        return sum;
    }
}
---------- END SOURCE ----------


Comments
Got a consistent error: java.lang.NullPointerException: Cannot invoke "String.length()" because the return value of "java.util.List.getLast()" is null at Test.main(Test.java:12) When testing with: OpenJDK 64-Bit Server VM (build 21.0.1+12-29, mixed mode, sharing) Java HotSpot(TM) 64-Bit Server VM (build 21.0.5+9-LTS-239, mixed mode, sharing) Java HotSpot(TM) 64-Bit Server VM (build 22.0.1+8-16, mixed mode, sharing) OpenJDK 64-Bit Server VM (build 22.0.2+9-70, mixed mode, sharing) Java HotSpot(TM) 64-Bit Server VM (build 23.0.1+11-39, mixed mode, sharing) ILW = Tests that are blocking further testing, Consistent failure in a test, No viable workaround = HHH => P1 Moved to JDK
14-05-2025