commit 18c0d5b0fa0d821c4944973bd6798e9ccaf2796e
parent 8d5c41fc538cba48221ef9d8ba9b852e9f04240f
Author: Charlie Gordon <github@chqrlie.org>
Date: Sat, 17 Feb 2024 21:15:29 +0100
Fix UB signed integer overflow in js_math_imul
- Use uint32_t arithmetics and Standard conformant conversion to
avoid UB in js_math_imul.
- add builtin tests
- use specific object directories for SAN targets
Diffstat:
3 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/quickjs/Makefile b/quickjs/Makefile
@@ -56,6 +56,16 @@ CONFIG_BIGNUM=y
OBJDIR=.obj
+ifdef CONFIG_ASAN
+OBJDIR:=$(OBJDIR)/asan
+endif
+ifdef CONFIG_MSAN
+OBJDIR:=$(OBJDIR)/msan
+endif
+ifdef CONFIG_UBSAN
+OBJDIR:=$(OBJDIR)/ubsan
+endif
+
ifdef CONFIG_DARWIN
# use clang instead of gcc
CONFIG_CLANG=y
diff --git a/quickjs/quickjs.c b/quickjs/quickjs.c
@@ -43310,14 +43310,16 @@ static double js_math_fround(double a)
static JSValue js_math_imul(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
- int a, b;
+ uint32_t a, b, c;
+ int32_t d;
- if (JS_ToInt32(ctx, &a, argv[0]))
+ if (JS_ToUint32(ctx, &a, argv[0]))
return JS_EXCEPTION;
- if (JS_ToInt32(ctx, &b, argv[1]))
+ if (JS_ToUint32(ctx, &b, argv[1]))
return JS_EXCEPTION;
- /* purposely ignoring overflow */
- return JS_NewInt32(ctx, a * b);
+ c = a * b;
+ memcpy(&d, &c, sizeof(d));
+ return JS_NewInt32(ctx, d);
}
static JSValue js_math_clz32(JSContext *ctx, JSValueConst this_val,
diff --git a/quickjs/tests/test_builtin.js b/quickjs/tests/test_builtin.js
@@ -311,6 +311,10 @@ function test_math()
assert(Math.floor(a), 1);
assert(Math.ceil(a), 2);
assert(Math.imul(0x12345678, 123), -1088058456);
+ assert(Math.imul(0xB505, 0xB504), 2147441940);
+ assert(Math.imul(0xB505, 0xB505), -2147479015);
+ assert(Math.imul((-2)**31, (-2)**31), 0);
+ assert(Math.imul(2**31-1, 2**31-1), 1);
assert(Math.fround(0.1), 0.10000000149011612);
assert(Math.hypot() == 0);
assert(Math.hypot(-2) == 2);