JDK-8287921 : FastThrow breaks Throwable.addSuppressed
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.lang
  • Priority: P4
  • Status: New
  • Resolution: Unresolved
  • Submitted: 2022-06-07
  • Updated: 2023-09-28
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.
Other
tbdUnresolved
Related Reports
Relates :  
Relates :  
Relates :  
Description
Throwable#addSuppressed is used for combining exceptions when two
independent exceptions can be thrown from the same code block. Typical case
is try-with-resources where one exception is from try block, and another
from closing resource.

#addSuppressed internally verifies that suppressed exception and current
exception are not the same. That is a reasonable condition to check, but it
doesn't seem to work well with fast throw optimization when exceptions are
being replaced with the same class instance, and that condition starts to
fail.

Consider the example below: it finishes successfully with
-XX:-OmitStackTraceInFastThrow flag, and fails with
IllegalArgumentException "Self-suppression not permitted" if optimization
is enabled.

public class Test {
    static class SomeCloseable implements AutoCloseable {
        @Override
        public void close() {
            throwsNPE();
        }
    }

    static void throwsNPE() {
        ((Object) null).getClass();
    }

    //run with and without -XX:-OmitStackTraceInFastThrow
    public static void main(String[] args) {
        for (int i = 0; i < 100_000; i++) {
            try (SomeCloseable c = new SomeCloseable()) {
                throwsNPE();
            } catch (NullPointerException expectedException) {
                assert expectedException.getSuppressed().length == 1;
            }
        }
    }
}

Could self match be no-op instead of exception in Throwable#addSuppressed?

See: https://mail.openjdk.java.net/pipermail/jdk-dev/2022-May/006718.html

Comments
Note that the check for self-suppression was added as part of JDK-6963622.
07-06-2022