Skip to content

Commit 06c100c

Browse files
committed
Prevent UB on memcpy and floating point conversions
- add `memcpy_no_ub` that accepts null pointers for 0 count - prevent 0 length allocation in `js_worker_postMessage` - use safer test for `int` value in `JS_NewFloat64`, `JS_ToArrayLengthFree` and `js_typed_array_indexOf`
1 parent 3dd93eb commit 06c100c

File tree

5 files changed

+26
-18
lines changed

5 files changed

+26
-18
lines changed

cutils.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ int dbuf_put(DynBuf *s, const uint8_t *data, size_t len)
140140
if (dbuf_realloc(s, s->size + len))
141141
return -1;
142142
}
143-
memcpy(s->buf + s->size, data, len);
143+
memcpy_no_ub(s->buf + s->size, data, len);
144144
s->size += len;
145145
return 0;
146146
}

cutils.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#define CUTILS_H
2727

2828
#include <stdlib.h>
29+
#include <string.h>
2930
#include <inttypes.h>
3031

3132
#define likely(x) __builtin_expect(!!(x), 1)
@@ -64,6 +65,12 @@ char *pstrcat(char *buf, int buf_size, const char *s);
6465
int strstart(const char *str, const char *val, const char **ptr);
6566
int has_suffix(const char *str, const char *suffix);
6667

68+
/* Prevent UB when n == 0 and (src == NULL or dest == NULL) */
69+
static inline void memcpy_no_ub(void *dest, const void *src, size_t n) {
70+
if (n)
71+
memcpy(dest, src, n);
72+
}
73+
6774
static inline int max_int(int a, int b)
6875
{
6976
if (a > b)

libbf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ int bf_set(bf_t *r, const bf_t *a)
309309
}
310310
r->sign = a->sign;
311311
r->expn = a->expn;
312-
memcpy(r->tab, a->tab, a->len * sizeof(limb_t));
312+
memcpy_no_ub(r->tab, a->tab, a->len * sizeof(limb_t));
313313
return 0;
314314
}
315315

quickjs.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11078,6 +11078,8 @@ static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
1107811078
if (JS_TAG_IS_FLOAT64(tag)) {
1107911079
double d;
1108011080
d = JS_VALUE_GET_FLOAT64(val);
11081+
if (!(d >= 0 && d <= UINT32_MAX))
11082+
goto fail;
1108111083
len = (uint32_t)d;
1108211084
if (len != d)
1108311085
goto fail;
@@ -33388,8 +33390,8 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
3338833390
}
3338933391
} else {
3339033392
b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
33391-
memcpy(b->vardefs, fd->args, fd->arg_count * sizeof(fd->args[0]));
33392-
memcpy(b->vardefs + fd->arg_count, fd->vars, fd->var_count * sizeof(fd->vars[0]));
33393+
memcpy_no_ub(b->vardefs, fd->args, fd->arg_count * sizeof(fd->args[0]));
33394+
memcpy_no_ub(b->vardefs + fd->arg_count, fd->vars, fd->var_count * sizeof(fd->vars[0]));
3339333395
}
3339433396
b->var_count = fd->var_count;
3339533397
b->arg_count = fd->arg_count;
@@ -53997,9 +53999,10 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
5399753999
} else
5399854000
if (tag == JS_TAG_FLOAT64) {
5399954001
d = JS_VALUE_GET_FLOAT64(argv[0]);
54000-
// XXX: should fix UB
54001-
v64 = d;
54002-
is_int = (v64 == d);
54002+
if (d >= INT64_MIN && d < 0x1p63) {
54003+
v64 = d;
54004+
is_int = (v64 == d);
54005+
}
5400354006
} else if (tag == JS_TAG_BIG_INT) {
5400454007
JSBigFloat *p1 = JS_VALUE_GET_PTR(argv[0]);
5400554008

quickjs.h

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -550,23 +550,21 @@ JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v);
550550

551551
static js_force_inline JSValue JS_NewFloat64(JSContext *ctx, double d)
552552
{
553-
JSValue v;
554553
int32_t val;
555554
union {
556555
double d;
557556
uint64_t u;
558557
} u, t;
559-
u.d = d;
560-
val = (int32_t)d;
561-
t.d = val;
562-
/* -0 cannot be represented as integer, so we compare the bit
563-
representation */
564-
if (u.u == t.u) {
565-
v = JS_MKVAL(JS_TAG_INT, val);
566-
} else {
567-
v = __JS_NewFloat64(ctx, d);
558+
if (d >= INT32_MIN && d <= INT32_MAX) {
559+
u.d = d;
560+
val = (int32_t)d;
561+
t.d = val;
562+
/* -0 cannot be represented as integer, so we compare the bit
563+
representation */
564+
if (u.u == t.u)
565+
return JS_MKVAL(JS_TAG_INT, val);
568566
}
569-
return v;
567+
return __JS_NewFloat64(ctx, d);
570568
}
571569

572570
static inline JS_BOOL JS_IsNumber(JSValueConst v)

0 commit comments

Comments
 (0)