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`
This commit is contained in:
parent
3dd93eb4e4
commit
06c100c9bf
5 changed files with 26 additions and 18 deletions
2
cutils.c
2
cutils.c
|
@ -140,7 +140,7 @@ int dbuf_put(DynBuf *s, const uint8_t *data, size_t len)
|
||||||
if (dbuf_realloc(s, s->size + len))
|
if (dbuf_realloc(s, s->size + len))
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
memcpy(s->buf + s->size, data, len);
|
memcpy_no_ub(s->buf + s->size, data, len);
|
||||||
s->size += len;
|
s->size += len;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
7
cutils.h
7
cutils.h
|
@ -26,6 +26,7 @@
|
||||||
#define CUTILS_H
|
#define CUTILS_H
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
#define likely(x) __builtin_expect(!!(x), 1)
|
#define likely(x) __builtin_expect(!!(x), 1)
|
||||||
|
@ -64,6 +65,12 @@ char *pstrcat(char *buf, int buf_size, const char *s);
|
||||||
int strstart(const char *str, const char *val, const char **ptr);
|
int strstart(const char *str, const char *val, const char **ptr);
|
||||||
int has_suffix(const char *str, const char *suffix);
|
int has_suffix(const char *str, const char *suffix);
|
||||||
|
|
||||||
|
/* Prevent UB when n == 0 and (src == NULL or dest == NULL) */
|
||||||
|
static inline void memcpy_no_ub(void *dest, const void *src, size_t n) {
|
||||||
|
if (n)
|
||||||
|
memcpy(dest, src, n);
|
||||||
|
}
|
||||||
|
|
||||||
static inline int max_int(int a, int b)
|
static inline int max_int(int a, int b)
|
||||||
{
|
{
|
||||||
if (a > b)
|
if (a > b)
|
||||||
|
|
2
libbf.c
2
libbf.c
|
@ -309,7 +309,7 @@ int bf_set(bf_t *r, const bf_t *a)
|
||||||
}
|
}
|
||||||
r->sign = a->sign;
|
r->sign = a->sign;
|
||||||
r->expn = a->expn;
|
r->expn = a->expn;
|
||||||
memcpy(r->tab, a->tab, a->len * sizeof(limb_t));
|
memcpy_no_ub(r->tab, a->tab, a->len * sizeof(limb_t));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11078,6 +11078,8 @@ static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
|
||||||
if (JS_TAG_IS_FLOAT64(tag)) {
|
if (JS_TAG_IS_FLOAT64(tag)) {
|
||||||
double d;
|
double d;
|
||||||
d = JS_VALUE_GET_FLOAT64(val);
|
d = JS_VALUE_GET_FLOAT64(val);
|
||||||
|
if (!(d >= 0 && d <= UINT32_MAX))
|
||||||
|
goto fail;
|
||||||
len = (uint32_t)d;
|
len = (uint32_t)d;
|
||||||
if (len != d)
|
if (len != d)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -33388,8 +33390,8 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
|
b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
|
||||||
memcpy(b->vardefs, fd->args, fd->arg_count * sizeof(fd->args[0]));
|
memcpy_no_ub(b->vardefs, fd->args, fd->arg_count * sizeof(fd->args[0]));
|
||||||
memcpy(b->vardefs + fd->arg_count, fd->vars, fd->var_count * sizeof(fd->vars[0]));
|
memcpy_no_ub(b->vardefs + fd->arg_count, fd->vars, fd->var_count * sizeof(fd->vars[0]));
|
||||||
}
|
}
|
||||||
b->var_count = fd->var_count;
|
b->var_count = fd->var_count;
|
||||||
b->arg_count = fd->arg_count;
|
b->arg_count = fd->arg_count;
|
||||||
|
@ -53997,9 +53999,10 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
|
||||||
} else
|
} else
|
||||||
if (tag == JS_TAG_FLOAT64) {
|
if (tag == JS_TAG_FLOAT64) {
|
||||||
d = JS_VALUE_GET_FLOAT64(argv[0]);
|
d = JS_VALUE_GET_FLOAT64(argv[0]);
|
||||||
// XXX: should fix UB
|
if (d >= INT64_MIN && d < 0x1p63) {
|
||||||
v64 = d;
|
v64 = d;
|
||||||
is_int = (v64 == d);
|
is_int = (v64 == d);
|
||||||
|
}
|
||||||
} else if (tag == JS_TAG_BIG_INT) {
|
} else if (tag == JS_TAG_BIG_INT) {
|
||||||
JSBigFloat *p1 = JS_VALUE_GET_PTR(argv[0]);
|
JSBigFloat *p1 = JS_VALUE_GET_PTR(argv[0]);
|
||||||
|
|
||||||
|
|
10
quickjs.h
10
quickjs.h
|
@ -550,23 +550,21 @@ JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v);
|
||||||
|
|
||||||
static js_force_inline JSValue JS_NewFloat64(JSContext *ctx, double d)
|
static js_force_inline JSValue JS_NewFloat64(JSContext *ctx, double d)
|
||||||
{
|
{
|
||||||
JSValue v;
|
|
||||||
int32_t val;
|
int32_t val;
|
||||||
union {
|
union {
|
||||||
double d;
|
double d;
|
||||||
uint64_t u;
|
uint64_t u;
|
||||||
} u, t;
|
} u, t;
|
||||||
|
if (d >= INT32_MIN && d <= INT32_MAX) {
|
||||||
u.d = d;
|
u.d = d;
|
||||||
val = (int32_t)d;
|
val = (int32_t)d;
|
||||||
t.d = val;
|
t.d = val;
|
||||||
/* -0 cannot be represented as integer, so we compare the bit
|
/* -0 cannot be represented as integer, so we compare the bit
|
||||||
representation */
|
representation */
|
||||||
if (u.u == t.u) {
|
if (u.u == t.u)
|
||||||
v = JS_MKVAL(JS_TAG_INT, val);
|
return JS_MKVAL(JS_TAG_INT, val);
|
||||||
} else {
|
|
||||||
v = __JS_NewFloat64(ctx, d);
|
|
||||||
}
|
}
|
||||||
return v;
|
return __JS_NewFloat64(ctx, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline JS_BOOL JS_IsNumber(JSValueConst v)
|
static inline JS_BOOL JS_IsNumber(JSValueConst v)
|
||||||
|
|
Loading…
Reference in a new issue