-
Enhancement
-
Resolution: Fixed
-
P4
-
17
-
b12
-
s390x
This is an old bug in the s390 template interpreter which has been there since the day the s390 port was contributed; it has been dormant however and was activated just recently by JDK-8250989 which changed the way class space reservation happens at CDS dump time.
It surfaced first as crash in runtime/cds/appcds/cacheObject/DifferentHeapSizes.java .
-----
If Compressed class pointer base has a non-zero value it may cause MacroAssembler::encode_klass_not_null() to encode a Klass pointer to a wrong narrow pointer.
This can be reproduced by starting the VM with
```
-Xshare:dump -XX:HeapBaseMinAddress=2g -Xmx128m
```
but CDS is not involved. It is only relevant insofar as this is the only way to get the following combination:
- heap is allocated at 0x800_0000. It is small and ends at 0x8800_0000.
- class space follows at 0x8800_0000
- the narrow klass pointer base points to the start of the class space at 0x8800_0000.
It is not possible with an unmodified VM to get the same combination of values with Xshare=on or Xshare=off.
-----
In MacroAssembler::encode_klass_not_null(), there is the following section:
```
if (base != NULL) {
unsigned int base_h = ((unsigned long)base)>>32;
unsigned int base_l = (unsigned int)((unsigned long)base);
if ((base_h != 0) && (base_l == 0) && VM_Version::has_HighWordInstr()) {
lgr_if_needed(dst, current);
z_aih(dst, -((int)base_h)); // Base has no set bits in lower half.
A } else if ((base_h == 0) && (base_l != 0)) {
lgr_if_needed(dst, current);
B z_agfi(dst, -(int)base_l);
} else {
load_const(Z_R0, base);
lgr_if_needed(dst, current);
z_sgr(dst, Z_R0);
}
current = dst;
}
```
We enter the condition at (A) if the narrow klass pointer base is non-zero but fits into 32bit. At (B), we want to substract the base from the Klass pointer; we do this by calculating the 32bit twos-complement of the base and add it with AGFI. AGFI adds a 32bit immediate to a 64bit register. In this case, it produces the wrong result if the base is >0x800_0000:
In the case of the crash, we have:
base:
8800_0000
32bit two's complement of base:
7800_0000
klass pointer:
8804_1040
klass pointer+7800_0000:
1_0004_1040
So the result of the "substraction" is 1_0004_1040, it should be 4_1040, which would be the correct offset of the Klass* pointer within the ccs. This wrong Klass* pointer then gets encoded and written into the Object header. VM crashes the first time the Klass pointer is decoded (which is pretty fast).
It surfaced first as crash in runtime/cds/appcds/cacheObject/DifferentHeapSizes.java .
-----
If Compressed class pointer base has a non-zero value it may cause MacroAssembler::encode_klass_not_null() to encode a Klass pointer to a wrong narrow pointer.
This can be reproduced by starting the VM with
```
-Xshare:dump -XX:HeapBaseMinAddress=2g -Xmx128m
```
but CDS is not involved. It is only relevant insofar as this is the only way to get the following combination:
- heap is allocated at 0x800_0000. It is small and ends at 0x8800_0000.
- class space follows at 0x8800_0000
- the narrow klass pointer base points to the start of the class space at 0x8800_0000.
It is not possible with an unmodified VM to get the same combination of values with Xshare=on or Xshare=off.
-----
In MacroAssembler::encode_klass_not_null(), there is the following section:
```
if (base != NULL) {
unsigned int base_h = ((unsigned long)base)>>32;
unsigned int base_l = (unsigned int)((unsigned long)base);
if ((base_h != 0) && (base_l == 0) && VM_Version::has_HighWordInstr()) {
lgr_if_needed(dst, current);
z_aih(dst, -((int)base_h)); // Base has no set bits in lower half.
A } else if ((base_h == 0) && (base_l != 0)) {
lgr_if_needed(dst, current);
B z_agfi(dst, -(int)base_l);
} else {
load_const(Z_R0, base);
lgr_if_needed(dst, current);
z_sgr(dst, Z_R0);
}
current = dst;
}
```
We enter the condition at (A) if the narrow klass pointer base is non-zero but fits into 32bit. At (B), we want to substract the base from the Klass pointer; we do this by calculating the 32bit twos-complement of the base and add it with AGFI. AGFI adds a 32bit immediate to a 64bit register. In this case, it produces the wrong result if the base is >0x800_0000:
In the case of the crash, we have:
base:
8800_0000
32bit two's complement of base:
7800_0000
klass pointer:
8804_1040
klass pointer+7800_0000:
1_0004_1040
So the result of the "substraction" is 1_0004_1040, it should be 4_1040, which would be the correct offset of the Klass* pointer within the ccs. This wrong Klass* pointer then gets encoded and written into the Object header. VM crashes the first time the Klass pointer is decoded (which is pretty fast).
- relates to
-
JDK-8250989 Consolidate buffer allocation code for CDS static/dynamic dumping
- Resolved