JDK-8233019 : java.lang.Class.isPrimitive() (C1) returns wrong result if Klass* is aligned to 32bit
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 9,10,11,12,13,14
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • CPU: x86
  • Submitted: 2019-10-25
  • Updated: 2023-11-27
  • Resolved: 2019-11-05
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 11 JDK 13 JDK 14 Other
11.0.7Fixed 13.0.4Fixed 14 b22Fixed openjdk8u352Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Description
A Klass* allocated at a 32bit aligned address (all lower 32 bits set to zero) may cause jlClass::isPrimitive() to return the wrong value.

The reason is that the C1 intrinsic for jlClass::isPrimitive(), which compares the Klass* address with NULL, does so using a 32bit compare:

-------------

 6512 Compiled method (c1)     822   31       1       java.lang.invoke.MethodTypeForm::canonicalize (233 bytes)
..<snip>..

 6544  ;;  block B2 [9, 13]
 6545   0x00007f2ca8e76f3f:   mov    0x50(%rsi),%rdi              ; implicit exception: dispatches to 0x00007f2ca8e771ec
 6546   0x00007f2ca8e76f43:   cmp    $0x0,%edi      <<<< 32bit?
 6547   0x00007f2ca8e76f46:   mov    $0x0,%edi
 6548   0x00007f2ca8e76f4b:   jne    0x00007f2ca8e76f56
 6549   0x00007f2ca8e76f51:   mov    $0x1,%edi                    ;*invokevirtual isPrimitive {reexecute=0 rethrow=0 return_oop=0}
 6550                                                             ; - java.lang.invoke.MethodTypeForm::canonicalize@10 (line 263)

-------------

Reproduce:

This is not possible to reproduce in the stock VM (though it could happen, albeit with very low probability). 

However, in the new metaspace allocator under development for JDK-8221173 chunk headers are removed from metaspace and therefore the very first Klass* ever to be allocated is located directly at class space start, which may be aligned to 32bit. 

This very first Klass* usually belongs to boolean[].class.

CDS needs to be off for this to happen. 

To reproduce, sync jdk-sandbox, branch "stuefe-new-metaspace-branch".

Then apply the following patch to force class space to a rounded address:

--- a/src/hotspot/share/memory/metaspace.cpp    Sat Oct 19 09:26:24 2019 +0200
+++ b/src/hotspot/share/memory/metaspace.cpp    Fri Oct 25 15:40:32 2019 +0200
@@ -828,6 +828,8 @@
 #ifdef _LP64
     if (using_class_space()) {
       char* base = (char*)align_up(CompressedOops::end(), _reserve_alignment);
+    base= (char*)0xb00000000ULL;
       allocate_metaspace_compressed_klass_ptrs(base, 0);
     }
 #endif // _LP64

(any address with 32bits set to zero will do).

and build.

Then run the jtreg test "java/util/stream/test/org/openjdk/tests/java/util/stream/StreamCloseTest.java", with CDS disabled. It will show an internal error related to isPrimitive() for boolean[].class being wrong. 



Comments
Fix Request [8u] This fix has been reviewed on github now.
17-06-2022

A pull request was submitted for review. URL: https://git.openjdk.java.net/jdk8u-dev/pull/43 Date: 2022-04-20 09:14:28 +0000
20-04-2022

Adding jdk8u-needs-pr. This fix needs to be rebased on to the current GitHub 8u-dev repository - https://github.com/openjdk/jdk8u-dev - and reviewed there before being approved and integrated.
14-04-2022

8u RFR thread: https://mail.openjdk.java.net/pipermail/jdk8u-dev/2021-December/014476.html
15-12-2021

Fix request (13u): The original change applies cleanly, except two files where a little context update is required due to absence of the fix for JDK-8230505. The change tested on linux x86_64 with tier1 and supplied regression test. RFR: https://mail.openjdk.java.net/pipermail/jdk-updates-dev/2020-June/003253.html
08-06-2020

Fix Request (11u) This resolves the corner case that leads to incorrect result for C1 intrinsic. Patch does not apply cleanly to 11u due to context changes. Patched JDK passes tier1, tier2, tier3 suites. 11u RFR (done): https://mail.openjdk.java.net/pipermail/jdk-updates-dev/2020-February/002448.html
05-02-2020

URL: https://hg.openjdk.java.net/jdk/jdk/rev/9bbe560e8131 User: stuefe Date: 2019-11-05 08:23:46 +0000
05-11-2019

ILW = C1 intrinsic for jlClass::isPrimitive() returns incorrect result, intermittent with C1 compiled code, disable intrinsic = HLM = P3
29-10-2019