Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8233019

java.lang.Class.isPrimitive() (C1) returns wrong result if Klass* is aligned to 32bit

XMLWordPrintable

    • b112
    • 9
    • b22
    • x86

        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.


              stuefe Thomas Stuefe
              stuefe Thomas Stuefe
              Votes:
              0 Vote for this issue
              Watchers:
              8 Start watching this issue

                Created:
                Updated:
                Resolved: