8331725: ubsan: pc may not always be the entry point for a VtableStub

Reviewed-by: kvn, mbaesken
This commit is contained in:
Axel Boldt-Christmas 2024-07-10 16:12:40 +00:00
parent fb9a227e02
commit fb66716a1b
2 changed files with 33 additions and 14 deletions

View File

@ -255,6 +255,19 @@ inline uint VtableStubs::hash(bool is_vtable_stub, int vtable_index){
}
inline uint VtableStubs::unsafe_hash(address entry_point) {
// The entrypoint may or may not be a VtableStub. Generate a hash as if it was.
address vtable_stub_addr = entry_point - VtableStub::entry_offset();
assert(CodeCache::contains(vtable_stub_addr), "assumed to always be the case");
address vtable_type_addr = vtable_stub_addr + offset_of(VtableStub, _type);
address vtable_index_addr = vtable_stub_addr + offset_of(VtableStub, _index);
bool is_vtable_stub = *vtable_type_addr == static_cast<uint8_t>(VtableStub::Type::vtable_stub);
int vtable_index;
memcpy(&vtable_index, vtable_index_addr, sizeof(vtable_index));
return hash(is_vtable_stub, vtable_index);
}
VtableStub* VtableStubs::lookup(bool is_vtable_stub, int vtable_index) {
assert_lock_strong(VtableStubs_lock);
unsigned hash = VtableStubs::hash(is_vtable_stub, vtable_index);
@ -275,12 +288,15 @@ void VtableStubs::enter(bool is_vtable_stub, int vtable_index, VtableStub* s) {
}
VtableStub* VtableStubs::entry_point(address pc) {
// The pc may or may not be the entry point for a VtableStub. Use unsafe_hash
// to generate the hash that would have been used if it was. The lookup in the
// _table will only succeed if there is a VtableStub with an entry point at
// the pc.
MutexLocker ml(VtableStubs_lock, Mutex::_no_safepoint_check_flag);
VtableStub* stub = (VtableStub*)(pc - VtableStub::entry_offset());
uint hash = VtableStubs::hash(stub->is_vtable_stub(), stub->index());
uint hash = VtableStubs::unsafe_hash(pc);
VtableStub* s;
for (s = Atomic::load(&_table[hash]); s != nullptr && s != stub; s = s->next()) {}
return (s == stub) ? s : nullptr;
for (s = Atomic::load(&_table[hash]); s != nullptr && s->entry_point() != pc; s = s->next()) {}
return (s != nullptr && s->entry_point() == pc) ? s : nullptr;
}
bool VtableStubs::contains(address pc) {

View File

@ -28,7 +28,6 @@
#include "asm/macroAssembler.hpp"
#include "code/vmreg.hpp"
#include "memory/allStatic.hpp"
#include "sanitizers/ub.hpp"
#include "utilities/checkedCast.hpp"
// A VtableStub holds an individual code stub for a pair (vtable index, #args) for either itables or vtables
@ -94,6 +93,7 @@ class VtableStubs : AllStatic {
static VtableStub* lookup (bool is_vtable_stub, int vtable_index);
static void enter (bool is_vtable_stub, int vtable_index, VtableStub* s);
static inline uint hash (bool is_vtable_stub, int vtable_index);
static inline uint unsafe_hash (address entry_point);
static address find_stub (bool is_vtable_stub, int vtable_index);
static void bookkeeping(MacroAssembler* masm, outputStream* out, VtableStub* s,
address npe_addr, address ame_addr, bool is_vtable_stub,
@ -119,6 +119,12 @@ class VtableStub {
private:
friend class VtableStubs;
enum class Type : uint8_t {
itable_stub,
vtable_stub,
};
static address _chunk; // For allocation
static address _chunk_end; // For allocation
static VMReg _receiver_location; // Where to find receiver
@ -127,14 +133,14 @@ class VtableStub {
const short _index; // vtable index
short _ame_offset; // Where an AbstractMethodError might occur
short _npe_offset; // Where a NullPointerException might occur
bool _is_vtable_stub; // True if vtable stub, false, is itable stub
Type _type; // Type, either vtable stub or itable stub
/* code follows here */ // The vtableStub code
void* operator new(size_t size, int code_size) throw();
VtableStub(bool is_vtable_stub, short index)
: _next(nullptr), _index(index), _ame_offset(-1), _npe_offset(-1),
_is_vtable_stub(is_vtable_stub) {}
_type(is_vtable_stub ? Type::vtable_stub : Type::itable_stub) {}
VtableStub* next() const { return _next; }
int index() const { return _index; }
static VMReg receiver_location() { return _receiver_location; }
@ -142,12 +148,12 @@ class VtableStub {
public:
address code_begin() const { return (address)(this + 1); }
address code_end() const { return code_begin() + VtableStubs::code_size_limit(_is_vtable_stub); }
address code_end() const { return code_begin() + VtableStubs::code_size_limit(is_vtable_stub()); }
address entry_point() const { return code_begin(); }
static int entry_offset() { return sizeof(class VtableStub); }
bool matches(bool is_vtable_stub, int index) const {
return _index == index && _is_vtable_stub == is_vtable_stub;
return _index == index && this->is_vtable_stub() == is_vtable_stub;
}
bool contains(address pc) const { return code_begin() <= pc && pc < code_end(); }
@ -173,11 +179,8 @@ class VtableStub {
public:
// Query
bool is_itable_stub() { return !_is_vtable_stub; }
// We reinterpret arbitrary memory as VtableStub. This does not cause failures because the lookup/equality
// check will reject false objects. Disabling UBSan is a temporary workaround until JDK-8331725 is fixed.
ATTRIBUTE_NO_UBSAN
bool is_vtable_stub() { return _is_vtable_stub; }
bool is_itable_stub() const { return _type == Type::itable_stub; }
bool is_vtable_stub() const { return _type == Type::vtable_stub; }
bool is_abstract_method_error(address epc) { return epc == code_begin()+_ame_offset; }
bool is_null_pointer_exception(address epc) { return epc == code_begin()+_npe_offset; }