mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 07:58:11 +00:00
AK+LibJS: Handle NaN-boxing pointers on AArch64
JS::Value stores 48 bit pointers to separately allocated objects in its payload. On x86-64, canonical addresses have their top 16 bits set to the same value as bit 47, effectively meaning that the value has to be sign-extended to get the pointer. AArch64, however, expects the topmost bits to be all zeros. This commit gates sign extension behind `#if ARCH(X86_64)`, and adds an `#error` for unsupported architectures, so that we do not forget to think about pointer handling when porting to a new architecture. Fixes #15290 Fixes SerenityOS/ladybird#56
This commit is contained in:
parent
62fed2a31d
commit
2b69af2dfe
4 changed files with 42 additions and 24 deletions
|
@ -39,25 +39,18 @@ TEST_NULLPTR_INPUT(Accessor);
|
|||
|
||||
#undef TEST_NULLPTR_INPUT
|
||||
|
||||
// Unfortunately we don't have a way to get the pointer without it being dereferenced
|
||||
// so we just use the same logic, this is dangerous if Value is ever changed!
|
||||
static u64 extract_pointer(u64 ptr)
|
||||
{
|
||||
return (u64)(((i64)(ptr << 16)) >> 16);
|
||||
}
|
||||
|
||||
TEST_CASE(valid_pointer_in_gives_same_pointer_out)
|
||||
{
|
||||
if (sizeof(void*) < sizeof(double))
|
||||
return;
|
||||
|
||||
#define EXPECT_POINTER_TO_SURVIVE(input) \
|
||||
{ \
|
||||
JS::Value value(reinterpret_cast<Object*>(static_cast<u64>(input))); \
|
||||
EXPECT(value.is_object()); \
|
||||
EXPECT(!value.is_null()); \
|
||||
auto extracted_pointer = extract_pointer(value.encoded()); \
|
||||
EXPECT_EQ(static_cast<u64>(input), extracted_pointer); \
|
||||
#define EXPECT_POINTER_TO_SURVIVE(input) \
|
||||
{ \
|
||||
JS::Value value(reinterpret_cast<Object*>(static_cast<u64>(input))); \
|
||||
EXPECT(value.is_object()); \
|
||||
EXPECT(!value.is_null()); \
|
||||
auto extracted_pointer = JS::Value::extract_pointer_bits(value.encoded()); \
|
||||
EXPECT_EQ(static_cast<u64>(input), extracted_pointer); \
|
||||
}
|
||||
|
||||
EXPECT_POINTER_TO_SURVIVE(0x1);
|
||||
|
@ -66,9 +59,18 @@ TEST_CASE(valid_pointer_in_gives_same_pointer_out)
|
|||
EXPECT_POINTER_TO_SURVIVE(0x00007fffffffffff);
|
||||
EXPECT_POINTER_TO_SURVIVE(0x0000700000000000);
|
||||
EXPECT_POINTER_TO_SURVIVE(0x0000100000000000);
|
||||
|
||||
#if ARCH(X86_64)
|
||||
// On x86-64, the top 16 bits of pointers are equal to bit 47.
|
||||
EXPECT_POINTER_TO_SURVIVE(0xffff800000000000);
|
||||
EXPECT_POINTER_TO_SURVIVE(0xffff800000000001);
|
||||
EXPECT_POINTER_TO_SURVIVE(0xffff800000000010);
|
||||
#elif ARCH(AARCH64)
|
||||
// ... but they should contain zeroes on AArch64.
|
||||
EXPECT_POINTER_TO_SURVIVE(0x0000800000000000);
|
||||
EXPECT_POINTER_TO_SURVIVE(0x0000800000000001);
|
||||
EXPECT_POINTER_TO_SURVIVE(0x0000800000000010);
|
||||
#endif
|
||||
|
||||
#undef EXPECT_POINTER_TO_SURVIVE
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue