diff options
author | davidot <davidot@serenityos.org> | 2022-09-07 01:14:23 +0200 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2022-09-10 00:05:32 +0100 |
commit | d4736d17aed3ea0f856c1237986d553a6616c6ca (patch) | |
tree | 2827393e15e7ec3dc359c8f7eb179aaa190a928e /Tests/LibJS | |
parent | 325263f0e8f300b1b85b8061a54eba11f7df48c6 (diff) | |
download | serenity-d4736d17aed3ea0f856c1237986d553a6616c6ca.zip |
LibJS: Allow negative pointers in Value
Also ensure that all a nullptr input gives null object and you don't
accidentally dereference a nullptr.
Diffstat (limited to 'Tests/LibJS')
-rw-r--r-- | Tests/LibJS/CMakeLists.txt | 3 | ||||
-rw-r--r-- | Tests/LibJS/test-value-js.cpp | 113 |
2 files changed, 116 insertions, 0 deletions
diff --git a/Tests/LibJS/CMakeLists.txt b/Tests/LibJS/CMakeLists.txt index 8b62b1cfaa..ce684ced41 100644 --- a/Tests/LibJS/CMakeLists.txt +++ b/Tests/LibJS/CMakeLists.txt @@ -8,3 +8,6 @@ link_with_locale_data(test-invalid-unicode-js) serenity_test(test-bytecode-js.cpp LibJS LIBS LibJS) link_with_locale_data(test-bytecode-js) + +serenity_test(test-value-js.cpp LibJS LIBS LibJS) +link_with_locale_data(test-value-js) diff --git a/Tests/LibJS/test-value-js.cpp b/Tests/LibJS/test-value-js.cpp new file mode 100644 index 0000000000..2b0fbdd959 --- /dev/null +++ b/Tests/LibJS/test-value-js.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2022, David Tuin <davidot@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibJS/Runtime/Value.h> +#include <LibTest/TestCase.h> + +using namespace JS; + +template<typename Type> +static void test_nullptr_input() +{ + Type* ptr = nullptr; + JS::Value val { ptr }; + EXPECT(val.is_null()); + EXPECT(!val.is_object()); + EXPECT(!val.is_string()); + EXPECT(!val.is_bigint()); + EXPECT(!val.is_symbol()); + EXPECT(!val.is_accessor()); + EXPECT(!val.is_cell()); + EXPECT(!val.is_number()); + EXPECT(!val.is_undefined()); +} + +#define TEST_NULLPTR_INPUT(type) \ + TEST_CASE(value_nullptr_input_##type) \ + { \ + test_nullptr_input<type>(); \ + } + +TEST_NULLPTR_INPUT(Object); +TEST_NULLPTR_INPUT(PrimitiveString); +TEST_NULLPTR_INPUT(Symbol); +TEST_NULLPTR_INPUT(BigInt); +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); \ + } + + EXPECT_POINTER_TO_SURVIVE(0x1); + EXPECT_POINTER_TO_SURVIVE(0x10); + EXPECT_POINTER_TO_SURVIVE(0x100); + EXPECT_POINTER_TO_SURVIVE(0x00007fffffffffff); + EXPECT_POINTER_TO_SURVIVE(0x0000700000000000); + EXPECT_POINTER_TO_SURVIVE(0x0000100000000000); + EXPECT_POINTER_TO_SURVIVE(0xffff800000000000); + EXPECT_POINTER_TO_SURVIVE(0xffff800000000001); + EXPECT_POINTER_TO_SURVIVE(0xffff800000000010); + +#undef EXPECT_POINTER_TO_SURVIVE +} + +TEST_CASE(non_canon_nans) +{ +#define EXPECT_TO_BE_NAN(input) \ + { \ + Value val { bit_cast<double>(input) }; \ + EXPECT(val.is_nan()); \ + EXPECT(val.is_number()); \ + EXPECT(!val.is_integral_number()); \ + EXPECT(!val.is_finite_number()); \ + EXPECT(!val.is_infinity()); \ + EXPECT(!val.is_empty()); \ + EXPECT(!val.is_nullish()); \ + } + + EXPECT_TO_BE_NAN(CANON_NAN_BITS | 0x1); + EXPECT_TO_BE_NAN(CANON_NAN_BITS | 0x10); + EXPECT_TO_BE_NAN(CANON_NAN_BITS | (NULL_TAG << TAG_SHIFT)); + EXPECT_TO_BE_NAN(CANON_NAN_BITS | (UNDEFINED_TAG << TAG_SHIFT)); + EXPECT_TO_BE_NAN(CANON_NAN_BITS | (INT32_TAG << TAG_SHIFT) | 0x88); + EXPECT_TO_BE_NAN(CANON_NAN_BITS | (OBJECT_TAG << TAG_SHIFT)); + EXPECT_TO_BE_NAN(CANON_NAN_BITS | (OBJECT_TAG << TAG_SHIFT) | 0x1230); + EXPECT_TO_BE_NAN(CANON_NAN_BITS | (STRING_TAG << TAG_SHIFT)); + EXPECT_TO_BE_NAN(CANON_NAN_BITS | (STRING_TAG << TAG_SHIFT) | 0x1230); + + u64 sign_bit = 1ULL << 63; + + EXPECT_TO_BE_NAN(CANON_NAN_BITS | sign_bit | 0x1); + EXPECT_TO_BE_NAN(CANON_NAN_BITS | sign_bit | 0x10); + EXPECT_TO_BE_NAN(CANON_NAN_BITS | sign_bit | (NULL_TAG << TAG_SHIFT)); + EXPECT_TO_BE_NAN(CANON_NAN_BITS | sign_bit | (UNDEFINED_TAG << TAG_SHIFT)); + EXPECT_TO_BE_NAN(CANON_NAN_BITS | sign_bit | (INT32_TAG << TAG_SHIFT) | 0x88); + EXPECT_TO_BE_NAN(CANON_NAN_BITS | sign_bit | (OBJECT_TAG << TAG_SHIFT)); + EXPECT_TO_BE_NAN(CANON_NAN_BITS | sign_bit | (OBJECT_TAG << TAG_SHIFT) | 0x1230); + EXPECT_TO_BE_NAN(CANON_NAN_BITS | sign_bit | (STRING_TAG << TAG_SHIFT)); + EXPECT_TO_BE_NAN(CANON_NAN_BITS | sign_bit | (STRING_TAG << TAG_SHIFT) | 0x1230); + +#undef EXPECT_TO_BE_NAN +} |