JDK-8310489 : New test runtime/ClassInitErrors/TestStackOverflowDuringInit.java failed
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 22
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2023-06-20
  • Updated: 2024-01-03
  • Resolved: 2023-06-27
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 22
22 b04Fixed
Related Reports
Relates :  
Sub Tasks
JDK-8310862 :  
Description
Despite all the pre-integration testing on x64 this test failed in its first run in the actual tier 1 CI. The SOE is triggered in the wrong place.
Comments
Changeset: 39fa4e63 Author: David Holmes <dholmes@openjdk.org> Date: 2023-06-27 00:13:42 +0000 URL: https://git.openjdk.org/jdk/commit/39fa4e6371dffbe8e09f7dbeeed27194bf99b53e
27-06-2023

[~dcubed] Fixed the label. I'm not adding to PL now anyway.
26-06-2023

[~dholmes] - We usually add the 'problemlist' label after the ProblemListing changeset is integrated.
26-06-2023

I've extracted the essence of the test into a version that is easier to understand and documented the expect behaviour. I change to interpreter mode to remove any chance of JIT oddities.
26-06-2023

A pull request was submitted for review. URL: https://git.openjdk.org/jdk/pull/14648 Date: 2023-06-26 06:38:52 +0000
26-06-2023

My previous analysis was inaccurate. Here is the code: class a { Boolean b; { try { Long.valueOf(509505376256L); Boolean c = true ? new d().b : 5 != ((e)java.util.HashSet.newHashSet(301758).clone()).f; } finally { Long.valueOf(0); } } } Bear in mind that class 'd` extends class `a`. When the test passes the initial SOE happens here: Long.valueOf(509505376256L) -> Long.<init>(val) -> Number.<init>() <- SOE here we then hit the finally block: Long.valueOf(0); LongCache.<clinit> <- second SOE here and so LongCache is marked as erroneous and we get the class initialization error we expect later on. In the failing case the initial SOE hits when we invoke d.<init>() and we then hit the finally block, but this time Long.valueof throws the SOE immediately and we don't reach the <clinit> of LongCache. However, this is strange because we throw SOE when invoking d.<init>(), yet immediately before that we successfully called Long.valueOf(509505376256L). Now you could explain that if Long.valueOf got inlined, but in that case why would d.<init> not also get inlined?
26-06-2023

So the way this test works is that it has the form: void recurse() { try { recurse(); } finally { x(); } } so the call to recurse() eventually throws SOE and we try to invoke x() which fails, in a predictable way, by also throwing SOE. When this test fails we see the original SOE being thrown, indicating that x() succeeded. So somehow the initial SOE is not thrown directly by the attempt to invoke recurse(), but by something incidental that requires a more significant amount of stack, such that when the SOE is thrown and we start the finally block, we've already freed up enough stack for the call to x() to complete successfully. I can make the test more robust by allowing for x() to succeed in these rare instances, but it would hide if we actually stopped testing what the test is trying to test - the correct capture of the SOE as the cause of a class initialization failure. If I could get the failure to reproduce I would be able to investigate what code actually causes the initial "unexpected" SOE.
22-06-2023

SOE is one of those exceptions that we probably can't use to reliably test anything.
21-06-2023