Around GC verification code, we often use Metaspace::contains to verify that klass word makes sense, and points to a proper Klass*. This, is however, is too optimistic: Metaspace::contains seems to only check that the address is within the virtual space.
In one of the debugging cases I am seeing in Shenandoah+Leyden, we have a object that passes checks for Metaspace::contains(obj->klass_or_null()), but the klass points straight to BlockTree::Node, which AFAICS is only used for free lists. In other words, we are pointing to a dead klass. A more common failure is in asserts, when we try to do assert(k->is_klass(), ...), invoke is_klass() virtual, reinterpreting canary as vtable, leading to SEGV.
I added the following code in Shenandoah Verifier to catch one of those cases in tests:
https://github.com/openjdk/jdk/blob/8b6e2770a53002fcc9e07d38b954e6854a644f95/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp#L225-L235
```
if (klass != nullptr && *((uint32_t*)klass) == 0x4e4f4445) {
fatal("Detected BlockTree Node canary instead of Klass: " PTR_FORMAT, p2i(klass));
}
```
...and it fails like this with https://github.com/openjdk/leyden/pull/8:
```
$ CONF=linux-x86_64-server-fastdebug make test TEST="runtime/cds/appcds/leyden/ExcludedClassesOldWF.java" TEST_VM_OPTS="-XX:+UseShenandoahGC -XX:+ShenandoahVerify -XX:ParallelGCThreads=1"
# A fatal error has been detected by the Java Runtime Environment:
#
# Internal Error (/home/shade/trunks/shipilev-leyden/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp:232), pid=367191, tid=367195
# fatal error: Detected BlockTree Node canary instead of Klass: 0x000000000d0ddcd0
```
I could not find Metaspace API that could tell me if the address that is within the Metaspace is "in use" instead of "free". If such API existed, we could have made stronger checks for Klass* validity.
In one of the debugging cases I am seeing in Shenandoah+Leyden, we have a object that passes checks for Metaspace::contains(obj->klass_or_null()), but the klass points straight to BlockTree::Node, which AFAICS is only used for free lists. In other words, we are pointing to a dead klass. A more common failure is in asserts, when we try to do assert(k->is_klass(), ...), invoke is_klass() virtual, reinterpreting canary as vtable, leading to SEGV.
I added the following code in Shenandoah Verifier to catch one of those cases in tests:
https://github.com/openjdk/jdk/blob/8b6e2770a53002fcc9e07d38b954e6854a644f95/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp#L225-L235
```
if (klass != nullptr && *((uint32_t*)klass) == 0x4e4f4445) {
fatal("Detected BlockTree Node canary instead of Klass: " PTR_FORMAT, p2i(klass));
}
```
...and it fails like this with https://github.com/openjdk/leyden/pull/8:
```
$ CONF=linux-x86_64-server-fastdebug make test TEST="runtime/cds/appcds/leyden/ExcludedClassesOldWF.java" TEST_VM_OPTS="-XX:+UseShenandoahGC -XX:+ShenandoahVerify -XX:ParallelGCThreads=1"
# A fatal error has been detected by the Java Runtime Environment:
#
# Internal Error (/home/shade/trunks/shipilev-leyden/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp:232), pid=367191, tid=367195
# fatal error: Detected BlockTree Node canary instead of Klass: 0x000000000d0ddcd0
```
I could not find Metaspace API that could tell me if the address that is within the Metaspace is "in use" instead of "free". If such API existed, we could have made stronger checks for Klass* validity.
- relates to
-
JDK-8340364 Shenandoah: Dead class mirrors crash GC
- Open