diff options
author | Daniel Bertalan <dani@danielbertalan.dev> | 2022-09-20 18:09:33 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-09-21 11:55:57 +0200 |
commit | 2b69af2dfe9ae2abaadee320878742a5c216deb4 (patch) | |
tree | 74d394d2f4c3e192d4dbfa01f1078f3947d43197 /Tests/LibJS | |
parent | 62fed2a31d9ff4de881deb0cf92d6061b09a7696 (diff) | |
download | serenity-2b69af2dfe9ae2abaadee320878742a5c216deb4.zip |
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
Diffstat (limited to 'Tests/LibJS')
-rw-r--r-- | Tests/LibJS/test-value-js.cpp | 30 |
1 files changed, 16 insertions, 14 deletions
diff --git a/Tests/LibJS/test-value-js.cpp b/Tests/LibJS/test-value-js.cpp index 2b0fbdd959..eac8c4463d 100644 --- a/Tests/LibJS/test-value-js.cpp +++ b/Tests/LibJS/test-value-js.cpp @@ -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 } |