Skip to content

Commit 6734b76

Browse files
committed
Tame UBsan applying zero offset to null pointer
It was possible, through different code paths to end up with an AB with a NULL data pointer or with a small 1 byte allocation. Normalize the logic so we don't allocate anything for a zero sized AB.
1 parent 7bc2ebf commit 6734b76

File tree

2 files changed

+78
-14
lines changed

2 files changed

+78
-14
lines changed

api-test.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,56 @@ static void immutable_array_buffer(void)
905905
JS_FreeRuntime(rt);
906906
}
907907

908+
static void get_uint8array(void)
909+
{
910+
JSRuntime *rt = JS_NewRuntime();
911+
JSContext *ctx = JS_NewContext(rt);
912+
JSValue val;
913+
uint8_t *p;
914+
size_t size;
915+
uint8_t buf[3] = { 1, 2, 3 };
916+
917+
val = eval(ctx, "new Uint8Array(0)");
918+
assert(!JS_IsException(val));
919+
p = JS_GetUint8Array(ctx, &size, val);
920+
assert(p == NULL);
921+
assert(size == 0);
922+
JS_FreeValue(ctx, val);
923+
924+
val = JS_NewUint8Array(ctx, NULL, 0, NULL, NULL, false);
925+
assert(!JS_IsException(val));
926+
p = JS_GetUint8Array(ctx, &size, val);
927+
assert(p == NULL);
928+
assert(size == 0);
929+
JS_FreeValue(ctx, val);
930+
931+
val = JS_NewUint8ArrayCopy(ctx, buf, sizeof(buf));
932+
assert(!JS_IsException(val));
933+
p = JS_GetUint8Array(ctx, &size, val);
934+
assert(p != NULL);
935+
assert(size == 3);
936+
assert(p[0] == 1 && p[1] == 2 && p[2] == 3);
937+
JS_FreeValue(ctx, val);
938+
939+
val = eval(ctx, "new Uint8Array([4, 5, 6])");
940+
assert(!JS_IsException(val));
941+
p = JS_GetUint8Array(ctx, &size, val);
942+
assert(p != NULL);
943+
assert(size == 3);
944+
assert(p[0] == 4 && p[1] == 5 && p[2] == 6);
945+
JS_FreeValue(ctx, val);
946+
947+
val = eval(ctx, "new Int32Array(4)");
948+
assert(!JS_IsException(val));
949+
p = JS_GetUint8Array(ctx, &size, val);
950+
assert(p == NULL);
951+
assert(size == 0);
952+
JS_FreeValue(ctx, val);
953+
954+
JS_FreeContext(ctx);
955+
JS_FreeRuntime(rt);
956+
}
957+
908958
int main(void)
909959
{
910960
cfunctions();
@@ -923,5 +973,6 @@ int main(void)
923973
global_object_prototype();
924974
slice_string_tocstring();
925975
immutable_array_buffer();
976+
get_uint8array();
926977
return 0;
927978
}

quickjs.c

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56156,9 +56156,13 @@ static JSValue js_array_buffer_constructor3(JSContext *ctx,
5615656156
memset(abuf->data, 0, sab_alloc_len);
5615756157
} else {
5615856158
/* the allocation must be done after the object creation */
56159-
abuf->data = js_mallocz(ctx, max_int(len, 1));
56160-
if (!abuf->data)
56161-
goto fail;
56159+
if (len > 0) {
56160+
abuf->data = js_mallocz(ctx, len);
56161+
if (!abuf->data)
56162+
goto fail;
56163+
} else {
56164+
abuf->data = NULL;
56165+
}
5616256166
}
5616356167
} else {
5616456168
if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER &&
@@ -56173,7 +56177,7 @@ static JSValue js_array_buffer_constructor3(JSContext *ctx,
5617356177
abuf->shared = (class_id == JS_CLASS_SHARED_ARRAY_BUFFER);
5617456178
abuf->opaque = opaque;
5617556179
abuf->free_func = free_func;
56176-
if (alloc_flag && buf)
56180+
if (alloc_flag && buf && len > 0)
5617756181
memcpy(abuf->data, buf, len);
5617856182
JS_SetOpaqueInternal(obj, abuf);
5617956183
return obj;
@@ -56643,11 +56647,16 @@ static JSValue js_array_buffer_resize(JSContext *ctx, JSValueConst this_val,
5664356647
// 2 bytes big in A, and 1 byte big in B
5664456648
abuf->byte_length = len;
5664556649
} else {
56646-
data = js_realloc(ctx, abuf->data, max_int(len, 1));
56647-
if (!data)
56648-
return JS_EXCEPTION;
56649-
if (len > abuf->byte_length)
56650-
memset(&data[abuf->byte_length], 0, len - abuf->byte_length);
56650+
if (len > 0) {
56651+
data = js_realloc(ctx, abuf->data, len);
56652+
if (!data)
56653+
return JS_EXCEPTION;
56654+
if (len > abuf->byte_length)
56655+
memset(&data[abuf->byte_length], 0, len - abuf->byte_length);
56656+
} else {
56657+
js_free(ctx, abuf->data);
56658+
data = NULL;
56659+
}
5665156660
abuf->byte_length = len;
5665256661
abuf->data = data;
5665356662
}
@@ -56730,7 +56739,8 @@ static JSValue js_array_buffer_slice(JSContext *ctx,
5673056739
JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
5673156740
goto fail;
5673256741
}
56733-
memcpy(new_abuf->data, abuf->data + start, new_len);
56742+
if (new_len > 0)
56743+
memcpy(new_abuf->data, abuf->data + start, new_len);
5673456744
new_abuf->immutable = immutable;
5673556745
return new_obj;
5673656746
fail:
@@ -56943,7 +56953,7 @@ uint8_t *JS_GetUint8Array(JSContext *ctx, size_t *psize, JSValueConst obj)
5694356953
abuf = ta->buffer->u.array_buffer;
5694456954

5694556955
*psize = ta->length;
56946-
return abuf->data + ta->offset;
56956+
return abuf->data ? abuf->data + ta->offset : NULL;
5694756957
fail:
5694856958
*psize = 0;
5694956959
return NULL;
@@ -57010,8 +57020,10 @@ static JSValue js_typed_array_set_internal(JSContext *ctx,
5701057020
/* copying between typed objects */
5701157021
if (src_p->class_id == p->class_id) {
5701257022
/* same type, use memmove */
57013-
memmove(dest_abuf->data + dest_ta->offset + (offset << shift),
57014-
src_abuf->data + src_ta->offset, src_len << shift);
57023+
if (src_len > 0) {
57024+
memmove(dest_abuf->data + dest_ta->offset + (offset << shift),
57025+
src_abuf->data + src_ta->offset, src_len << shift);
57026+
}
5701557027
goto done;
5701657028
}
5701757029
if (dest_abuf->data == src_abuf->data) {
@@ -58718,7 +58730,8 @@ static JSValue js_typed_array_constructor_ta(JSContext *ctx,
5871858730
goto fail;
5871958731
if (p->class_id == classid) {
5872058732
/* same type: copy the content */
58721-
memcpy(abuf->data, src_abuf->data + ta->offset, abuf->byte_length);
58733+
if (abuf->byte_length > 0)
58734+
memcpy(abuf->data, src_abuf->data + ta->offset, abuf->byte_length);
5872258735
} else {
5872358736
for(i = 0; i < len; i++) {
5872458737
JSValue val;

0 commit comments

Comments
 (0)