[aarch64-port-dev ] RFR: 8148783: aarch64: SEGV running SpecJBB2013
Andrew Haley
aph at redhat.com
Tue Feb 2 15:16:13 UTC 2016
Hi,
On 02/01/2016 08:33 PM, Edward Nevill wrote:
> JIRA Issue: https://bugs.openjdk.java.net/browse/JDK-8148783
>
> The bug is explained in some detail in the JIRA issue.
>
> The problem is that the sign is not preserved in the following code
> from adrp(...)
>
> long offset = dest_page - pc_page;
> offset = (offset & ((1<<20)-1)) << 12;
>
> This generally works because the following movk overwrites bits 32..47
>
> However on larger memory systems of 256 Gb it could happen that the
> PC address was
>
> 0x0000ffffXXXXXXXX
>
> in which case the falsely positive offset could wrap to
>
> 0x00010000XXXXXXXX
>
> Bit 48 does not get overwritten by the following movk, hence forming
> an invalid address.
>
> The solution is to use int32_t for offset instead of long, so it
> gets sign extended correctly when added to the pc().
I can't accept that patch because the overflowing assignment from long
to int32_t is undefined behaviour. It is also very obscure code.
Can you test the patch I've appended instead? It tiptoes around the UB
and should be OK.
Thanks,
Andrew.
diff --git a/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp b/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp
--- a/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp
+++ b/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp
@@ -3980,6 +3980,14 @@
return inst_mark();
}
+int64_t MacroAssembler::truncate_signed_bitfield(int64_t n, int width) {
+ // Left shifts of a signed integer are UB in Standard C++ but
+ // well-defined in GNU C++.
+ n <<= 64 - width;
+ n >>= 64 - width;
+ return n;
+}
+
void MacroAssembler::adrp(Register reg1, const Address &dest, unsigned long &byte_offset) {
relocInfo::relocType rtype = dest.rspec().reloc()->type();
unsigned long low_page = (unsigned long)CodeCache::low_bound() >> 12;
@@ -3999,8 +4007,18 @@
_adrp(reg1, dest.target());
} else {
unsigned long pc_page = (unsigned long)pc() >> 12;
- long offset = dest_page - pc_page;
- offset = (offset & ((1<<20)-1)) << 12;
+ unsigned long page_offset = dest_page - pc_page;
+
+ // The signed offset (in 4k pages) from PC to dest page. We use a
+ // reference in order to avoid UB when converting from unsigned to
+ // signed.
+ long offset = reinterpret_cast<long&>(page_offset);
+
+ // The signed offset (in bytes) from the PC to the destination
+ // page. We only want the 32 LSBs of the offset because the range
+ // of ADRP is +-2G, i.e. 32 bits.
+ offset = truncate_signed_bitfield(offset << 12, 32);
+
_adrp(reg1, pc()+offset);
movk(reg1, (unsigned long)dest.target() >> 32, 32);
}
diff --git a/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp b/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp
--- a/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp
+++ b/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp
@@ -85,9 +85,10 @@
void call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions = true);
- // Maximum size of class area in Metaspace when compressed
uint64_t use_XOR_for_compressed_class_base;
+ int64_t truncate_signed_bitfield(int64_t n, int width);
+
public:
MacroAssembler(CodeBuffer* code) : Assembler(code) {
use_XOR_for_compressed_class_base
More information about the hotspot-compiler-dev
mailing list