diff --git a/src/modules/buffer.c b/src/modules/buffer.c index 8fe128c..414d548 100644 --- a/src/modules/buffer.c +++ b/src/modules/buffer.c @@ -3194,6 +3194,25 @@ static ant_value_t js_buffer_copy(ant_t *js, ant_value_t *args, int nargs) { return js_mknum((double)copy_len); } +static bool buffer_checked_byte_offset( + ant_value_t value, + size_t byte_length, + size_t width, + size_t *out +) { + double offset_num = vtype(value) == T_NUM ? js_getnum(value) : 0.0; + if (!isfinite(offset_num) || offset_num < 0) return false; + + offset_num = floor(offset_num); + if (offset_num > (double)byte_length) return false; + + size_t offset = (size_t)offset_num; + if (width > byte_length || offset > byte_length - width) return false; + + *out = offset; + return true; +} + static ant_value_t js_buffer_writeInt16BE(ant_t *js, ant_value_t *args, int nargs) { if (nargs < 1) return js_mkerr(js, "writeInt16BE requires a value"); @@ -3201,8 +3220,9 @@ static ant_value_t js_buffer_writeInt16BE(ant_t *js, ant_value_t *args, int narg if (!ta) return js_mkerr(js, "Invalid Buffer"); int16_t value = (int16_t)js_to_int32(js_getnum(args[0])); - size_t offset = (nargs > 1 && vtype(args[1]) == T_NUM) ? (size_t)js_getnum(args[1]) : 0; - if (offset + 2 > ta->byte_length) return js_mkerr(js, "Offset out of bounds"); + size_t offset = 0; + if (!buffer_checked_byte_offset(nargs > 1 ? args[1] : js_mkundef(), ta->byte_length, 2, &offset)) + return js_mkerr(js, "Offset out of bounds"); uint8_t *ptr = ta->buffer->data + ta->byte_offset + offset; ptr[0] = (uint8_t)((value >> 8) & 0xff); @@ -3218,8 +3238,9 @@ static ant_value_t js_buffer_writeInt32BE(ant_t *js, ant_value_t *args, int narg if (!ta) return js_mkerr(js, "Invalid Buffer"); int32_t value = js_to_int32(js_getnum(args[0])); - size_t offset = (nargs > 1 && vtype(args[1]) == T_NUM) ? (size_t)js_getnum(args[1]) : 0; - if (offset + 4 > ta->byte_length) return js_mkerr(js, "Offset out of bounds"); + size_t offset = 0; + if (!buffer_checked_byte_offset(nargs > 1 ? args[1] : js_mkundef(), ta->byte_length, 4, &offset)) + return js_mkerr(js, "Offset out of bounds"); uint8_t *ptr = ta->buffer->data + ta->byte_offset + offset; ptr[0] = (uint8_t)((value >> 24) & 0xff); @@ -3237,8 +3258,9 @@ static ant_value_t js_buffer_writeUInt32BE(ant_t *js, ant_value_t *args, int nar if (!ta) return js_mkerr(js, "Invalid Buffer"); uint32_t value = js_to_uint32(js_getnum(args[0])); - size_t offset = (nargs > 1 && vtype(args[1]) == T_NUM) ? (size_t)js_getnum(args[1]) : 0; - if (offset + 4 > ta->byte_length) return js_mkerr(js, "Offset out of bounds"); + size_t offset = 0; + if (!buffer_checked_byte_offset(nargs > 1 ? args[1] : js_mkundef(), ta->byte_length, 4, &offset)) + return js_mkerr(js, "Offset out of bounds"); uint8_t *ptr = ta->buffer->data + ta->byte_offset + offset; ptr[0] = (uint8_t)((value >> 24) & 0xff); @@ -3256,8 +3278,9 @@ static ant_value_t js_buffer_writeUInt16BE(ant_t *js, ant_value_t *args, int nar if (!ta) return js_mkerr(js, "Invalid Buffer"); uint16_t value = (uint16_t)js_to_uint32(js_getnum(args[0])); - size_t offset = (nargs > 1 && vtype(args[1]) == T_NUM) ? (size_t)js_getnum(args[1]) : 0; - if (offset + 2 > ta->byte_length) return js_mkerr(js, "Offset out of bounds"); + size_t offset = 0; + if (!buffer_checked_byte_offset(nargs > 1 ? args[1] : js_mkundef(), ta->byte_length, 2, &offset)) + return js_mkerr(js, "Offset out of bounds"); uint8_t *ptr = ta->buffer->data + ta->byte_offset + offset; ptr[0] = (uint8_t)((value >> 8) & 0xff); @@ -3274,11 +3297,12 @@ static ant_value_t js_buffer_writeUIntBE(ant_t *js, ant_value_t *args, int nargs double number = js_to_number(js, args[0]); uint64_t value = (uint64_t)(isnan(number) || number < 0 ? 0 : floor(number)); - size_t offset = (size_t)js_getnum(args[1]); size_t byte_length = (size_t)js_getnum(args[2]); + size_t offset = 0; if (byte_length == 0 || byte_length > 6) return js_mkerr(js, "byteLength out of range"); - if (offset + byte_length > ta->byte_length) return js_mkerr(js, "Offset out of bounds"); + if (!buffer_checked_byte_offset(args[1], ta->byte_length, byte_length, &offset)) + return js_mkerr(js, "Offset out of bounds"); uint8_t *ptr = ta->buffer->data + ta->byte_offset + offset; for (size_t i = byte_length; i > 0; i--) { @@ -3293,8 +3317,9 @@ static ant_value_t js_buffer_readInt16BE(ant_t *js, ant_value_t *args, int nargs TypedArrayData *ta = buffer_get_typedarray_data(js_getthis(js)); if (!ta) return js_mkerr(js, "Invalid Buffer"); - size_t offset = (nargs > 0 && vtype(args[0]) == T_NUM) ? (size_t)js_getnum(args[0]) : 0; - if (offset + 2 > ta->byte_length) return js_mkerr(js, "Offset out of bounds"); + size_t offset = 0; + if (!buffer_checked_byte_offset(nargs > 0 ? args[0] : js_mkundef(), ta->byte_length, 2, &offset)) + return js_mkerr(js, "Offset out of bounds"); uint8_t *ptr = ta->buffer->data + ta->byte_offset + offset; int16_t value = (int16_t)((ptr[0] << 8) | ptr[1]); @@ -3306,8 +3331,9 @@ static ant_value_t js_buffer_readUInt16BE(ant_t *js, ant_value_t *args, int narg TypedArrayData *ta = buffer_get_typedarray_data(js_getthis(js)); if (!ta) return js_mkerr(js, "Invalid Buffer"); - size_t offset = (nargs > 0 && vtype(args[0]) == T_NUM) ? (size_t)js_getnum(args[0]) : 0; - if (offset + 2 > ta->byte_length) return js_mkerr(js, "Offset out of bounds"); + size_t offset = 0; + if (!buffer_checked_byte_offset(nargs > 0 ? args[0] : js_mkundef(), ta->byte_length, 2, &offset)) + return js_mkerr(js, "Offset out of bounds"); uint8_t *ptr = ta->buffer->data + ta->byte_offset + offset; uint16_t value = (uint16_t)(((uint16_t)ptr[0] << 8) | (uint16_t)ptr[1]); @@ -3319,8 +3345,9 @@ static ant_value_t js_buffer_readInt32BE(ant_t *js, ant_value_t *args, int nargs TypedArrayData *ta = buffer_get_typedarray_data(js_getthis(js)); if (!ta) return js_mkerr(js, "Invalid Buffer"); - size_t offset = (nargs > 0 && vtype(args[0]) == T_NUM) ? (size_t)js_getnum(args[0]) : 0; - if (offset + 4 > ta->byte_length) return js_mkerr(js, "Offset out of bounds"); + size_t offset = 0; + if (!buffer_checked_byte_offset(nargs > 0 ? args[0] : js_mkundef(), ta->byte_length, 4, &offset)) + return js_mkerr(js, "Offset out of bounds"); uint8_t *ptr = ta->buffer->data + ta->byte_offset + offset; int32_t value = (int32_t)(((uint32_t)ptr[0] << 24) | ((uint32_t)ptr[1] << 16) | @@ -3333,8 +3360,9 @@ static ant_value_t js_buffer_readUInt32BE(ant_t *js, ant_value_t *args, int narg TypedArrayData *ta = buffer_get_typedarray_data(js_getthis(js)); if (!ta) return js_mkerr(js, "Invalid Buffer"); - size_t offset = (nargs > 0 && vtype(args[0]) == T_NUM) ? (size_t)js_getnum(args[0]) : 0; - if (offset + 4 > ta->byte_length) return js_mkerr(js, "Offset out of bounds"); + size_t offset = 0; + if (!buffer_checked_byte_offset(nargs > 0 ? args[0] : js_mkundef(), ta->byte_length, 4, &offset)) + return js_mkerr(js, "Offset out of bounds"); uint8_t *ptr = ta->buffer->data + ta->byte_offset + offset; uint32_t value = ((uint32_t)ptr[0] << 24) | ((uint32_t)ptr[1] << 16) | diff --git a/src/modules/net.c b/src/modules/net.c index c63fbb0..7270e80 100644 --- a/src/modules/net.c +++ b/src/modules/net.c @@ -27,6 +27,7 @@ #include "modules/events.h" #include "modules/net.h" #include "modules/symbol.h" +#include "modules/timer.h" typedef struct net_server_s net_server_t; typedef struct net_socket_s net_socket_t; @@ -459,6 +460,34 @@ static void net_socket_emit_error(net_socket_t *socket, const char *message) { net_emit(socket->js, socket->obj, "error", &arg, 1); } +static ant_value_t net_socket_emit_connect_error(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t state = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); + ant_value_t socket_obj = is_object_type(state) ? js_get(js, state, "socket") : js_mkundef(); + ant_value_t status_val = is_object_type(state) ? js_get(js, state, "status") : js_mknum(UV_EIO); + + net_socket_t *socket = net_socket_data(socket_obj); + int status = vtype(status_val) == T_NUM ? (int)js_getnum(status_val) : UV_EIO; + + ant_value_t err = 0; + if (!socket) return js_mkundef(); + + socket->connecting = false; + socket->had_error = true; + net_socket_sync_state(socket); + err = js_mkerr_typed(js, JS_ERR_TYPE, "%s", uv_strerror(status)); + net_emit(js, socket->obj, "error", &err, 1); + if (socket->conn) ant_conn_close(socket->conn); + + return js_mkundef(); +} + +static void net_socket_schedule_connect_error(ant_t *js, net_socket_t *socket, int status) { + ant_value_t state = js_mkobj(js); + js_set(js, state, "socket", socket->obj); + js_set(js, state, "status", js_mknum((double)status)); + queue_microtask(js, js_heavy_mkfun(js, net_socket_emit_connect_error, state)); +} + static net_socket_t *net_socket_create(ant_t *js, bool allow_half_open) { ant_value_t obj = js_mkobj(js); ant_value_t proto = js_instance_proto_from_new_target(js, g_net_socket_proto); @@ -907,9 +936,7 @@ static ant_value_t net_socket_connect_parsed(ant_t *js, net_socket_t *socket, co socket->connecting = false; socket->had_error = true; net_socket_sync_state(socket); - ant_value_t err = js_mkerr_typed(js, JS_ERR_TYPE, "%s", uv_strerror(rc)); - net_emit(js, socket->obj, "error", &err, 1); - ant_conn_close(conn); + net_socket_schedule_connect_error(js, socket, rc); } return socket->obj; diff --git a/tests/test_buffer_indexof.cjs b/tests/test_buffer_indexof.cjs index 9ae6e02..86358bc 100644 --- a/tests/test_buffer_indexof.cjs +++ b/tests/test_buffer_indexof.cjs @@ -39,7 +39,24 @@ function assertThrowsTypeError(fn) { assert.fail('expected TypeError'); } +function assertThrows(fn) { + try { + fn(); + } catch { + return; + } + assert.fail('expected throw'); +} + assertThrowsTypeError(() => Buffer.from('abc').indexOf({})); assertThrowsTypeError(() => Buffer.from('abc').indexOf('a', 0, 'not-an-encoding')); +{ + const b = Buffer.alloc(2); + assertThrows(() => b.writeUInt16BE(0x1234, -1)); + assert.deepStrictEqual([...b], [0, 0]); + assertThrows(() => b.writeUIntBE(0x1234, -1, 2)); + assertThrows(() => b.readUInt16BE(-1)); +} + console.log('buffer:indexof:ok'); diff --git a/tests/test_net_create_connection.cjs b/tests/test_net_create_connection.cjs index c58af38..ae64b13 100644 --- a/tests/test_net_create_connection.cjs +++ b/tests/test_net_create_connection.cjs @@ -1,14 +1,27 @@ const net = require('node:net'); +const assert = require('node:assert'); let connected = false; let serverSawData = false; let clientSawData = false; +let invalidHostError = false; const timeout = setTimeout(() => { - if (!connected || !serverSawData || !clientSawData) { + if (!connected || !serverSawData || !clientSawData || !invalidHostError) { throw new Error('net.createConnection timed out'); } }, 2000); +function finishWithInvalidHostCheck() { + const socket = net.connect({ host: 'definitely.invalid.ant.local', port: 80 }); + socket.on('error', (error) => { + invalidHostError = true; + assert(error instanceof Error); + assert.strictEqual(typeof error.message, 'string'); + clearTimeout(timeout); + console.log('net:create-connection:ok'); + }); +} + const server = net.createServer((socket) => { socket.setEncoding('utf8'); socket.on('data', (chunk) => { @@ -41,8 +54,7 @@ server.listen(0, '127.0.0.1', () => { if (!connected || !serverSawData || !clientSawData) { throw new Error('net.createConnection did not complete the loopback exchange'); } - clearTimeout(timeout); - console.log('net:create-connection:ok'); + finishWithInvalidHostCheck(); }); }); });