mirror of
https://github.com/bellard/quickjs.git
synced 2025-11-15 10:12:14 +03:00
Fix use-after-free in ArrayBuffer.prototype.transfer (bnoordhuis) (#450) - use js_array_buffer_update_typed_arrays() in JS_DetachArrayBuffer()
This commit is contained in:
82
quickjs.c
82
quickjs.c
@@ -55344,10 +55344,47 @@ static JSValue js_array_buffer_get_resizable(JSContext *ctx,
|
||||
return JS_NewBool(ctx, array_buffer_is_resizable(abuf));
|
||||
}
|
||||
|
||||
static void js_array_buffer_update_typed_arrays(JSArrayBuffer *abuf)
|
||||
{
|
||||
uint32_t size_log2, size_elem;
|
||||
struct list_head *el;
|
||||
JSTypedArray *ta;
|
||||
JSObject *p;
|
||||
uint8_t *data;
|
||||
int64_t len;
|
||||
|
||||
len = abuf->byte_length;
|
||||
data = abuf->data;
|
||||
// update lengths of all typed arrays backed by this array buffer
|
||||
list_for_each(el, &abuf->array_list) {
|
||||
ta = list_entry(el, JSTypedArray, link);
|
||||
p = ta->obj;
|
||||
if (p->class_id == JS_CLASS_DATAVIEW) {
|
||||
continue;
|
||||
} else {
|
||||
p->u.array.count = 0;
|
||||
p->u.array.u.ptr = NULL;
|
||||
size_log2 = typed_array_size_log2(p->class_id);
|
||||
size_elem = 1 << size_log2;
|
||||
if (ta->track_rab) {
|
||||
if (len >= (int64_t)ta->offset + size_elem) {
|
||||
p->u.array.count = (len - ta->offset) >> size_log2;
|
||||
p->u.array.u.ptr = &data[ta->offset];
|
||||
}
|
||||
} else {
|
||||
if (len >= (int64_t)ta->offset + ta->length) {
|
||||
p->u.array.count = ta->length >> size_log2;
|
||||
p->u.array.u.ptr = &data[ta->offset];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj)
|
||||
{
|
||||
JSArrayBuffer *abuf = JS_GetOpaque(obj, JS_CLASS_ARRAY_BUFFER);
|
||||
struct list_head *el;
|
||||
|
||||
if (!abuf || abuf->detached)
|
||||
return;
|
||||
@@ -55356,19 +55393,7 @@ void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj)
|
||||
abuf->data = NULL;
|
||||
abuf->byte_length = 0;
|
||||
abuf->detached = TRUE;
|
||||
|
||||
list_for_each(el, &abuf->array_list) {
|
||||
JSTypedArray *ta;
|
||||
JSObject *p;
|
||||
|
||||
ta = list_entry(el, JSTypedArray, link);
|
||||
p = ta->obj;
|
||||
/* Note: the typed array length and offset fields are not modified */
|
||||
if (p->class_id != JS_CLASS_DATAVIEW) {
|
||||
p->u.array.count = 0;
|
||||
p->u.array.u.ptr = NULL;
|
||||
}
|
||||
}
|
||||
js_array_buffer_update_typed_arrays(abuf);
|
||||
}
|
||||
|
||||
/* get an ArrayBuffer or SharedArrayBuffer */
|
||||
@@ -55483,6 +55508,7 @@ static JSValue js_array_buffer_transfer(JSContext *ctx,
|
||||
abuf->data = NULL;
|
||||
abuf->byte_length = 0;
|
||||
abuf->detached = TRUE;
|
||||
js_array_buffer_update_typed_arrays(abuf);
|
||||
return js_array_buffer_constructor3(ctx, JS_UNDEFINED, new_len, pmax_len,
|
||||
JS_CLASS_ARRAY_BUFFER,
|
||||
bs, free_func,
|
||||
@@ -55493,11 +55519,7 @@ static JSValue js_array_buffer_transfer(JSContext *ctx,
|
||||
static JSValue js_array_buffer_resize(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv, int class_id)
|
||||
{
|
||||
uint32_t size_log2, size_elem;
|
||||
struct list_head *el;
|
||||
JSArrayBuffer *abuf;
|
||||
JSTypedArray *ta;
|
||||
JSObject *p;
|
||||
uint8_t *data;
|
||||
int64_t len;
|
||||
|
||||
@@ -55540,29 +55562,7 @@ static JSValue js_array_buffer_resize(JSContext *ctx, JSValueConst this_val,
|
||||
abuf->byte_length = len;
|
||||
abuf->data = data;
|
||||
}
|
||||
data = abuf->data;
|
||||
// update lengths of all typed arrays backed by this array buffer
|
||||
list_for_each(el, &abuf->array_list) {
|
||||
ta = list_entry(el, JSTypedArray, link);
|
||||
p = ta->obj;
|
||||
if (p->class_id == JS_CLASS_DATAVIEW)
|
||||
continue;
|
||||
p->u.array.count = 0;
|
||||
p->u.array.u.ptr = NULL;
|
||||
size_log2 = typed_array_size_log2(p->class_id);
|
||||
size_elem = 1 << size_log2;
|
||||
if (ta->track_rab) {
|
||||
if (len >= (int64_t)ta->offset + size_elem) {
|
||||
p->u.array.count = (len - ta->offset) >> size_log2;
|
||||
p->u.array.u.ptr = &data[ta->offset];
|
||||
}
|
||||
} else {
|
||||
if (len >= (int64_t)ta->offset + ta->length) {
|
||||
p->u.array.count = ta->length >> size_log2;
|
||||
p->u.array.u.ptr = &data[ta->offset];
|
||||
}
|
||||
}
|
||||
}
|
||||
js_array_buffer_update_typed_arrays(abuf);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
|
||||
@@ -511,6 +511,14 @@ function test_typed_array()
|
||||
assert(a.toString(), "1,2,3,4");
|
||||
a.set([10, 11], 2);
|
||||
assert(a.toString(), "1,2,10,11");
|
||||
|
||||
// https://github.com/quickjs-ng/quickjs/issues/1208
|
||||
buffer = new ArrayBuffer(16);
|
||||
a = new Uint8Array(buffer);
|
||||
a.fill(42);
|
||||
assert(a[0], 42);
|
||||
buffer.transfer();
|
||||
assert(a[0], undefined);
|
||||
}
|
||||
|
||||
/* return [s, line_num, col_num] where line_num and col_num are the
|
||||
|
||||
Reference in New Issue
Block a user