diff options
author | Daniel Bertalan <dani@danielbertalan.dev> | 2021-08-06 20:42:36 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-08-08 10:55:36 +0200 |
commit | 12dc2c2079b5c9a23571f6dc01b258e381322f12 (patch) | |
tree | 11228a6a2965b1e764a9406642175b9255dc02b2 /Userland/Libraries/LibJS | |
parent | 0a05f04d1bc7fe6dd5ebaa8204c720b43bede626 (diff) | |
download | serenity-12dc2c2079b5c9a23571f6dc01b258e381322f12.zip |
LibJS: Fix wraparound UB in `Value::to_u{8,16}`
If we call these two functions on a negative value, undefined behavior
occurs due to casting a negative double to an unsigned integer. These
functions are defined to perform modular arithmetic, so negative values
can be fixed up by adding 2^8/2^16.
The reason why this step is not mentioned in ECMA-262 is that it defines
modular arithmetic so that `x mod m` had the same sign as `m`, while
LibM's `fmod(x, m)` copies `x`'s sign.
This issue was found by UBSAN with the Clang toolchain.
Diffstat (limited to 'Userland/Libraries/LibJS')
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/Value.cpp | 4 |
1 files changed, 4 insertions, 0 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/Value.cpp b/Userland/Libraries/LibJS/Runtime/Value.cpp index 76c6d4cc41..f2336f51cb 100644 --- a/Userland/Libraries/LibJS/Runtime/Value.cpp +++ b/Userland/Libraries/LibJS/Runtime/Value.cpp @@ -684,6 +684,8 @@ u16 Value::to_u16(GlobalObject& global_object) const if (signbit(value)) int_val = -int_val; auto int16bit = fmod(int_val, NumericLimits<u16>::max() + 1.0); + if (int16bit < 0) + int16bit += NumericLimits<u16>::max() + 1.0; return static_cast<u16>(int16bit); } @@ -720,6 +722,8 @@ u8 Value::to_u8(GlobalObject& global_object) const if (signbit(value)) int_val = -int_val; auto int8bit = fmod(int_val, NumericLimits<u8>::max() + 1.0); + if (int8bit < 0) + int8bit += NumericLimits<u8>::max() + 1.0; return static_cast<u8>(int8bit); } |