From 09ffe7ef277660198831fe495b72a05194a2963a Mon Sep 17 00:00:00 2001 From: Julia-Garland Date: Tue, 26 Aug 2025 10:28:17 -0400 Subject: [PATCH 01/13] Add bson_array_alloc function --- src/libbson/src/bson/memory.c | 36 +++++++++++++++++++++++++++++++++++ src/libbson/src/bson/memory.h | 2 ++ 2 files changed, 38 insertions(+) diff --git a/src/libbson/src/bson/memory.c b/src/libbson/src/bson/memory.c index 7a079a959f..be15675073 100644 --- a/src/libbson/src/bson/memory.c +++ b/src/libbson/src/bson/memory.c @@ -231,6 +231,42 @@ bson_aligned_alloc0(size_t alignment /* IN */, size_t num_bytes /* IN */) } +/* + *-------------------------------------------------------------------------- + * + * bson_array_alloc -- + * + * Allocates zero-filled, aligned memory for an array of objects, + * checking for cases of n = 0 and integer overflow in type_size * len, + * in which case NULL is returned. + * + * Parameters: + * @type_size: The size of each object's type in bytes. + * @len: The number of objects to allocate. + * + * Returns: + * A pointer if successful; otherwise abort() is called and this + * function will never return. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + +void * +bson_array_alloc(size_t type_size /* IN */, size_t len /* IN */) +{ + void *mem = NULL; + size_t num_bytes = type_size * len; + + if (BSON_LIKELY(num_bytes) && BSON_LIKELY(type_size == num_bytes / len)) { + mem = bson_aligned_alloc0(BSON_ALIGN_OF(type_size), num_bytes); + } + return mem; +} + + /* *-------------------------------------------------------------------------- * diff --git a/src/libbson/src/bson/memory.h b/src/libbson/src/bson/memory.h index 9c0957680f..e13aedfd30 100644 --- a/src/libbson/src/bson/memory.h +++ b/src/libbson/src/bson/memory.h @@ -48,6 +48,8 @@ bson_aligned_alloc(size_t alignment, size_t num_bytes); BSON_EXPORT(void *) bson_aligned_alloc0(size_t alignment, size_t num_bytes); BSON_EXPORT(void *) +bson_array_alloc(size_t type_size, size_t len); +BSON_EXPORT(void *) bson_realloc(void *mem, size_t num_bytes); BSON_EXPORT(void *) bson_realloc_ctx(void *mem, size_t num_bytes, void *ctx); From b06e4911fb1c2486492d26fe1143a1f738dc9304 Mon Sep 17 00:00:00 2001 From: Julia-Garland Date: Tue, 26 Aug 2025 11:12:52 -0400 Subject: [PATCH 02/13] Replace in situ multiplication with array_alloc function call --- src/common/src/common-bson-dsl-private.h | 36 +++++++++---------- src/libbson/src/jsonsl/jsonsl.c | 4 +-- src/libbson/tests/test-bson-vector.c | 18 +++++----- src/libmongoc/src/mongoc/mcd-rpc.c | 2 +- src/libmongoc/src/mongoc/mongoc-async-cmd.c | 2 +- .../mongoc/mongoc-client-side-encryption.c | 4 +-- .../src/mongoc/mongoc-cluster-sspi.c | 8 ++--- src/libmongoc/src/mongoc/mongoc-scram.c | 4 +-- .../src/mongoc/mongoc-secure-channel.c | 2 +- .../src/mongoc/mongoc-server-description.c | 2 +- src/libmongoc/src/mongoc/mongoc-set.c | 6 ++-- src/libmongoc/src/mongoc/mongoc-socket.c | 4 +-- src/libmongoc/src/mongoc/mongoc-sspi.c | 8 ++--- .../src/mongoc/mongoc-stream-socket.c | 2 +- src/libmongoc/src/mongoc/mongoc-stream.c | 2 +- .../mongoc-topology-background-monitoring.c | 2 +- .../src/mongoc/mongoc-topology-description.c | 4 +-- src/libmongoc/src/mongoc/mongoc-topology.c | 2 +- 18 files changed, 56 insertions(+), 56 deletions(-) diff --git a/src/common/src/common-bson-dsl-private.h b/src/common/src/common-bson-dsl-private.h index 2f20e1c6ca..4adcc6729e 100644 --- a/src/common/src/common-bson-dsl-private.h +++ b/src/common/src/common-bson-dsl-private.h @@ -659,24 +659,24 @@ BSON_IF_GNU_LIKE(_Pragma("GCC diagnostic ignored \"-Wshadow\"")) } \ } while (0); -#define _bsonParseMarkVisited(Index) \ - if (1) { \ - const size_t nth_int = Index / 64u; \ - const size_t nth_bit = Index % 64u; \ - while (nth_int >= _bpNumVisitBitInts) { \ - /* Say that five times, fast: */ \ - size_t new_num_visit_bit_ints = _bpNumVisitBitInts * 2u; \ - uint64_t *new_visit_bit_ints = bson_malloc0(sizeof(uint64_t) * new_num_visit_bit_ints); \ - memcpy(new_visit_bit_ints, _bpVisitBits, sizeof(uint64_t) * _bpNumVisitBitInts); \ - if (_bpVisitBits != _bpVisitBits_static) { \ - bson_free(_bpVisitBits); \ - } \ - _bpVisitBits = new_visit_bit_ints; \ - _bpNumVisitBitInts = new_num_visit_bit_ints; \ - } \ - \ - _bpVisitBits[nth_int] |= (UINT64_C(1) << nth_bit); \ - } else \ +#define _bsonParseMarkVisited(Index) \ + if (1) { \ + const size_t nth_int = Index / 64u; \ + const size_t nth_bit = Index % 64u; \ + while (nth_int >= _bpNumVisitBitInts) { \ + /* Say that five times, fast: */ \ + size_t new_num_visit_bit_ints = _bpNumVisitBitInts * 2u; \ + uint64_t *new_visit_bit_ints = bson_array_alloc(sizeof(uint64_t), new_num_visit_bit_ints); \ + memcpy(new_visit_bit_ints, _bpVisitBits, sizeof(uint64_t) * _bpNumVisitBitInts); \ + if (_bpVisitBits != _bpVisitBits_static) { \ + bson_free(_bpVisitBits); \ + } \ + _bpVisitBits = new_visit_bit_ints; \ + _bpNumVisitBitInts = new_num_visit_bit_ints; \ + } \ + \ + _bpVisitBits[nth_int] |= (UINT64_C(1) << nth_bit); \ + } else \ ((void)0) #define _bsonParseDidVisitNth(Index) _bsonParseDidVisitNth_1(Index / 64u, Index % 64u) diff --git a/src/libbson/src/jsonsl/jsonsl.c b/src/libbson/src/jsonsl/jsonsl.c index 56bb4c36cc..f71f517abe 100644 --- a/src/libbson/src/jsonsl/jsonsl.c +++ b/src/libbson/src/jsonsl/jsonsl.c @@ -1052,9 +1052,9 @@ void jsonsl_jpr_match_state_init(jsonsl_t jsn, if (njprs == 0) { return; } - jsn->jprs = (jsonsl_jpr_t *) bson_malloc (sizeof (jsonsl_jpr_t) * njprs); + jsn->jprs = (jsonsl_jpr_t *) bson_array_alloc (sizeof (jsonsl_jpr_t), njprs); jsn->jpr_count = njprs; - jsn->jpr_root = (size_t *) bson_malloc0 (sizeof (size_t) * njprs * jsn->levels_max); + jsn->jpr_root = (size_t *) bson_array_alloc (sizeof (size_t), njprs * jsn->levels_max); memcpy(jsn->jprs, jprs, sizeof(jsonsl_jpr_t) * njprs); /* Set the initial jump table values */ diff --git a/src/libbson/tests/test-bson-vector.c b/src/libbson/tests/test-bson-vector.c index c41384a2f2..6ef4296e05 100644 --- a/src/libbson/tests/test-bson-vector.c +++ b/src/libbson/tests/test-bson-vector.c @@ -920,8 +920,8 @@ test_bson_vector_view_api_fuzz_int8(void) { size_t current_length = 0; bson_t vector_doc = BSON_INITIALIZER; - int8_t *expected_elements = bson_malloc(MAX_TESTED_VECTOR_LENGTH * sizeof *expected_elements); - int8_t *actual_elements = bson_malloc(MAX_TESTED_VECTOR_LENGTH * sizeof *actual_elements); + int8_t *expected_elements = bson_array_alloc(sizeof *expected_elements, MAX_TESTED_VECTOR_LENGTH); + int8_t *actual_elements = bson_array_alloc(sizeof *actual_elements, MAX_TESTED_VECTOR_LENGTH); for (int fuzz_iter = 0; fuzz_iter < FUZZ_TEST_ITERS; fuzz_iter++) { unsigned r = (unsigned)rand(); unsigned r_operation = r & 0xFu; @@ -974,8 +974,8 @@ test_bson_vector_view_api_fuzz_float32(void) { size_t current_length = 0; bson_t vector_doc = BSON_INITIALIZER; - float *expected_elements = bson_malloc(MAX_TESTED_VECTOR_LENGTH * sizeof *expected_elements); - float *actual_elements = bson_malloc(MAX_TESTED_VECTOR_LENGTH * sizeof *actual_elements); + float *expected_elements = bson_array_alloc(sizeof *expected_elements, MAX_TESTED_VECTOR_LENGTH); + float *actual_elements = bson_array_alloc(sizeof *actual_elements, MAX_TESTED_VECTOR_LENGTH); for (int fuzz_iter = 0; fuzz_iter < FUZZ_TEST_ITERS; fuzz_iter++) { unsigned r = (unsigned)rand(); unsigned r_operation = r & 0xFu; @@ -1028,8 +1028,8 @@ test_bson_vector_view_api_fuzz_packed_bit(void) { size_t current_length = 0; bson_t vector_doc = BSON_INITIALIZER; - bool *expected_elements = bson_malloc(MAX_TESTED_VECTOR_LENGTH * sizeof *expected_elements); - bool *actual_elements = bson_malloc(MAX_TESTED_VECTOR_LENGTH * sizeof *actual_elements); + bool *expected_elements = bson_array_alloc(sizeof *expected_elements, MAX_TESTED_VECTOR_LENGTH); + bool *actual_elements = bson_array_alloc(sizeof *actual_elements, MAX_TESTED_VECTOR_LENGTH); uint8_t *packed_buffer = bson_malloc((MAX_TESTED_VECTOR_LENGTH + 7) / 8); for (int fuzz_iter = 0; fuzz_iter < FUZZ_TEST_ITERS; fuzz_iter++) { unsigned r = (unsigned)rand(); @@ -1392,7 +1392,7 @@ test_bson_vector_edge_cases_int8(void) // Test some read and write boundaries. { size_t values_size = 100; - int8_t *values = bson_malloc0(values_size * sizeof *values); + int8_t *values = bson_array_alloc(sizeof *values, values_size); TEST_BSON_VECTOR_EDGE_CASES_RW_COMMON( view, max_alloc_elements, values, values_size, bson_vector_int8_view_read, bson_vector_int8_view_write); bson_free(values); @@ -1439,7 +1439,7 @@ test_bson_vector_edge_cases_float32(void) // Test some read and write boundaries. { size_t values_size = 100; - float *values = bson_malloc0(values_size * sizeof *values); + float *values = bson_array_alloc(sizeof *values, values_size); TEST_BSON_VECTOR_EDGE_CASES_RW_COMMON( view, max_alloc_elements, values, values_size, bson_vector_float32_view_read, bson_vector_float32_view_write); bson_free(values); @@ -1506,7 +1506,7 @@ test_bson_vector_edge_cases_packed_bit(void) // Only tests one length, but it's chosen to be greater than 8 and not a multiple of 8. { size_t values_size = 190; - bool *values = bson_malloc0(values_size * sizeof *values); + bool *values = bson_array_alloc(sizeof *values, values_size); TEST_BSON_VECTOR_EDGE_CASES_RW_COMMON(view, max_alloc_elements, values, diff --git a/src/libmongoc/src/mongoc/mcd-rpc.c b/src/libmongoc/src/mongoc/mcd-rpc.c index 5cf681bc80..4832fb5cc5 100644 --- a/src/libmongoc/src/mongoc/mcd-rpc.c +++ b/src/libmongoc/src/mongoc/mcd-rpc.c @@ -957,7 +957,7 @@ _append_iovec_reserve_space_for(mongoc_iovec_t **iovecs, BSON_ASSERT(*capacity == 4u); *capacity += additional_capacity; - *iovecs = bson_malloc(*capacity * sizeof(mongoc_iovec_t)); + *iovecs = bson_array_alloc(sizeof(mongoc_iovec_t), *capacity); memcpy(*iovecs, header_iovecs, 4u * sizeof(mongoc_iovec_t)); } diff --git a/src/libmongoc/src/mongoc/mongoc-async-cmd.c b/src/libmongoc/src/mongoc/mongoc-async-cmd.c index 74eb5fda00..ad55a09e1d 100644 --- a/src/libmongoc/src/mongoc/mongoc-async-cmd.c +++ b/src/libmongoc/src/mongoc/mongoc-async-cmd.c @@ -339,7 +339,7 @@ _mongoc_async_cmd_phase_send(mongoc_async_cmd_t *acmd) /* create a new iovec with the remaining data to be written. */ niovec = acmd->niovec - i; - iovec = bson_malloc(niovec * sizeof(mongoc_iovec_t)); + iovec = bson_array_alloc(sizeof(mongoc_iovec_t), niovec); memcpy(iovec, acmd->iovec + i, niovec * sizeof(mongoc_iovec_t)); iovec[0].iov_base = (char *)iovec[0].iov_base + offset; iovec[0].iov_len -= offset; diff --git a/src/libmongoc/src/mongoc/mongoc-client-side-encryption.c b/src/libmongoc/src/mongoc/mongoc-client-side-encryption.c index f81ef3db4e..eff49d5cc9 100644 --- a/src/libmongoc/src/mongoc/mongoc-client-side-encryption.c +++ b/src/libmongoc/src/mongoc/mongoc-client-side-encryption.c @@ -409,7 +409,7 @@ mongoc_client_encryption_datakey_opts_set_keyaltnames(mongoc_client_encryption_d BSON_ASSERT(!opts->keyaltnames); if (keyaltnames_count) { - opts->keyaltnames = bson_malloc(sizeof(char *) * keyaltnames_count); + opts->keyaltnames = bson_array_alloc(sizeof(char *), keyaltnames_count); for (uint32_t i = 0u; i < keyaltnames_count; i++) { opts->keyaltnames[i] = bson_strdup(keyaltnames[i]); } @@ -1601,7 +1601,7 @@ _spawn_mongocryptd(const char *mongocryptd_spawn_path, const bson_t *mongocryptd num_args++; } - args = (char **)bson_malloc(sizeof(char *) * num_args); + args = (char **)bson_array_alloc(sizeof(char *), num_args); i = 0; args[i++] = "mongocryptd"; diff --git a/src/libmongoc/src/mongoc/mongoc-cluster-sspi.c b/src/libmongoc/src/mongoc/mongoc-cluster-sspi.c index eabd6292fb..4a260f3b9e 100644 --- a/src/libmongoc/src/mongoc/mongoc-cluster-sspi.c +++ b/src/libmongoc/src/mongoc/mongoc-cluster-sspi.c @@ -65,7 +65,7 @@ _mongoc_cluster_sspi_new(mongoc_uri_t *uri, mongoc_stream_t *stream, const char service_ascii_len = strlen(service_ascii); /* this is donated to the sspi */ - service = bson_malloc0((service_ascii_len + 1) * sizeof(WCHAR)); + service = bson_array_alloc(sizeof(WCHAR), (service_ascii_len + 1)); service_len = MultiByteToWideChar(CP_UTF8, 0, service_ascii, (int)service_ascii_len, service, (int)service_ascii_len); service[service_len] = L'\0'; @@ -75,7 +75,7 @@ _mongoc_cluster_sspi_new(mongoc_uri_t *uri, mongoc_stream_t *stream, const char tmp_creds_len = strlen(state->sasl.pass); /* this is donated to the sspi */ - pass = bson_malloc0((tmp_creds_len + 1) * sizeof(WCHAR)); + pass = bson_array_alloc(sizeof(WCHAR), (tmp_creds_len + 1)); pass_len = MultiByteToWideChar(CP_UTF8, 0, state->sasl.pass, (int)tmp_creds_len, pass, (int)tmp_creds_len); pass[pass_len] = L'\0'; } @@ -84,7 +84,7 @@ _mongoc_cluster_sspi_new(mongoc_uri_t *uri, mongoc_stream_t *stream, const char tmp_creds_len = strlen(state->sasl.user); /* this is donated to the sspi */ - user = bson_malloc0((tmp_creds_len + 1) * sizeof(WCHAR)); + user = bson_array_alloc(sizeof(WCHAR), (tmp_creds_len + 1)); user_len = MultiByteToWideChar(CP_UTF8, 0, state->sasl.user, (int)tmp_creds_len, user, (int)tmp_creds_len); user[user_len] = L'\0'; } @@ -222,7 +222,7 @@ _mongoc_cluster_auth_node_sspi(mongoc_cluster_t *cluster, tmpstr = bson_iter_utf8(&iter, &buflen); bson_free(buf); - buf = bson_malloc(sizeof(SEC_CHAR) * (buflen + 1)); + buf = bson_array_alloc(sizeof(SEC_CHAR), (buflen + 1)); memcpy(buf, tmpstr, buflen); buf[buflen] = (SEC_CHAR)0; diff --git a/src/libmongoc/src/mongoc/mongoc-scram.c b/src/libmongoc/src/mongoc/mongoc-scram.c index e068b387c8..84fe439fff 100644 --- a/src/libmongoc/src/mongoc/mongoc-scram.c +++ b/src/libmongoc/src/mongoc/mongoc-scram.c @@ -1026,7 +1026,7 @@ _mongoc_sasl_prep_impl(const char *name, const char *in_utf8, bson_error_t *err) /* convert to unicode. */ BSON_ASSERT(mlib_cmp(num_chars, <=, SIZE_MAX / sizeof(uint32_t) - 1)); - utf8_codepoints = bson_malloc(sizeof(uint32_t) * ((size_t)num_chars + 1u)); /* add one for trailing 0 value. */ + utf8_codepoints = bson_array_alloc(sizeof(uint32_t), ((size_t)num_chars + 1u)); /* add one for trailing 0 value. */ const char *c = in_utf8; mlib_foreach_irange (i, num_chars) { @@ -1083,7 +1083,7 @@ _mongoc_sasl_prep_impl(const char *name, const char *in_utf8, bson_error_t *err) utf8_pre_norm_len += len; } } - char *utf8_pre_norm = (char *)bson_malloc(sizeof(char) * (utf8_pre_norm_len + 1)); + char *utf8_pre_norm = (char *)bson_array_alloc(sizeof(char), (utf8_pre_norm_len + 1)); char *loc = utf8_pre_norm; mlib_foreach_irange (i, num_chars) { diff --git a/src/libmongoc/src/mongoc/mongoc-secure-channel.c b/src/libmongoc/src/mongoc/mongoc-secure-channel.c index 694a43cf6a..97c87bb3d2 100644 --- a/src/libmongoc/src/mongoc/mongoc-secure-channel.c +++ b/src/libmongoc/src/mongoc/mongoc-secure-channel.c @@ -233,7 +233,7 @@ utf8_to_wide(const char *utf8) } // Since -1 was passed as the input length, the returned character count includes space for the null character. - WCHAR *wide_chars = bson_malloc(sizeof(WCHAR) * required_wide_chars); + WCHAR *wide_chars = bson_array_alloc(sizeof(WCHAR), required_wide_chars); if (0 == MultiByteToWideChar(CP_UTF8, 0, utf8, -1 /* NULL terminated */, wide_chars, required_wide_chars)) { bson_free(wide_chars); return NULL; diff --git a/src/libmongoc/src/mongoc/mongoc-server-description.c b/src/libmongoc/src/mongoc/mongoc-server-description.c index b7212f7a79..da07c3d29c 100644 --- a/src/libmongoc/src/mongoc/mongoc-server-description.c +++ b/src/libmongoc/src/mongoc/mongoc-server-description.c @@ -987,7 +987,7 @@ mongoc_server_description_filter_tags(const mongoc_server_description_t **descri return; } - sd_matched = (bool *)bson_malloc0(sizeof(bool) * description_len); + sd_matched = (bool *)bson_array_alloc(sizeof(bool), description_len); bson_iter_init(&rp_tagset_iter, rp_tags); diff --git a/src/libmongoc/src/mongoc/mongoc-set.c b/src/libmongoc/src/mongoc/mongoc-set.c index 861ac446cb..dec8e162ab 100644 --- a/src/libmongoc/src/mongoc/mongoc-set.c +++ b/src/libmongoc/src/mongoc/mongoc-set.c @@ -27,7 +27,7 @@ mongoc_set_new(size_t nitems, mongoc_set_item_dtor dtor, void *dtor_ctx) mongoc_set_t *set = (mongoc_set_t *)bson_malloc(sizeof(*set)); set->items_allocated = BSON_MAX(nitems, 1); - set->items = (mongoc_set_item_t *)bson_malloc(sizeof(*set->items) * set->items_allocated); + set->items = (mongoc_set_item_t *)bson_array_alloc(sizeof(*set->items), set->items_allocated); set->items_len = 0; set->dtor = dtor; @@ -208,7 +208,7 @@ mongoc_set_for_each_with_id(mongoc_set_t *set, mongoc_set_for_each_with_id_cb_t return; } - mongoc_set_item_t *const old_set = bson_malloc(sizeof(*old_set) * items_len); + mongoc_set_item_t *const old_set = bson_array_alloc(sizeof(*old_set), items_len); memcpy(old_set, set->items, sizeof(*old_set) * items_len); for (uint32_t i = 0u; i < items_len; i++) { @@ -237,7 +237,7 @@ mongoc_set_for_each_with_id_const(const mongoc_set_t *set, mongoc_set_for_each_w return; } - mongoc_set_item_t *const old_set = bson_malloc(sizeof(*old_set) * items_len); + mongoc_set_item_t *const old_set = bson_array_alloc(sizeof(*old_set), items_len); memcpy(old_set, set->items, sizeof(*old_set) * items_len); for (uint32_t i = 0u; i < items_len; i++) { diff --git a/src/libmongoc/src/mongoc/mongoc-socket.c b/src/libmongoc/src/mongoc/mongoc-socket.c index cea764af9d..91af25d1b9 100644 --- a/src/libmongoc/src/mongoc/mongoc-socket.c +++ b/src/libmongoc/src/mongoc/mongoc-socket.c @@ -336,7 +336,7 @@ mongoc_socket_poll(mongoc_socket_poll_t *sds, /* IN */ } } #else - pfds = (struct pollfd *)bson_malloc(sizeof(*pfds) * nsds); + pfds = (struct pollfd *)bson_array_alloc(sizeof(*pfds), nsds); for (size_t i = 0u; i < nsds; i++) { pfds[i].fd = sds[i].socket->sd; @@ -1349,7 +1349,7 @@ mongoc_socket_sendv(mongoc_socket_t *sock, /* IN */ BSON_ASSERT(in_iov); BSON_ASSERT(iovcnt); - iov = bson_malloc(sizeof(*iov) * iovcnt); + iov = bson_array_alloc(sizeof(*iov), iovcnt); memcpy(iov, in_iov, sizeof(*iov) * iovcnt); for (;;) { diff --git a/src/libmongoc/src/mongoc/mongoc-sspi.c b/src/libmongoc/src/mongoc/mongoc-sspi.c index 6ac1043225..43b8d3f797 100644 --- a/src/libmongoc/src/mongoc/mongoc-sspi.c +++ b/src/libmongoc/src/mongoc/mongoc-sspi.c @@ -69,7 +69,7 @@ _mongoc_sspi_base64_encode(const SEC_CHAR *value, DWORD vlen) DWORD len; /* Get the correct size for the out buffer. */ if (CryptBinaryToStringA((BYTE *)value, vlen, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, NULL, &len)) { - out = (SEC_CHAR *)bson_malloc(sizeof(SEC_CHAR) * len); + out = (SEC_CHAR *)bson_array_alloc(sizeof(SEC_CHAR), len); if (out) { /* Encode to the out buffer. */ if (CryptBinaryToStringA((BYTE *)value, vlen, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, out, &len)) { @@ -89,7 +89,7 @@ _mongoc_sspi_base64_decode(const SEC_CHAR *value, DWORD *rlen) SEC_CHAR *out = NULL; /* Get the correct size for the out buffer. */ if (CryptStringToBinaryA(value, 0, CRYPT_STRING_BASE64, NULL, rlen, NULL, NULL)) { - out = (SEC_CHAR *)bson_malloc(sizeof(SEC_CHAR) * *rlen); + out = (SEC_CHAR *)bson_array_alloc(sizeof(SEC_CHAR), *rlen); if (out) { /* Decode to the out buffer. */ if (CryptStringToBinaryA(value, 0, CRYPT_STRING_BASE64, (BYTE *)out, rlen, NULL, NULL)) { @@ -109,7 +109,7 @@ _mongoc_sspi_wide_to_utf8(WCHAR *value) CHAR *out; int len = WideCharToMultiByte(CP_UTF8, 0, value, -1, NULL, 0, NULL, NULL); if (len) { - out = (CHAR *)bson_malloc(sizeof(CHAR) * len); + out = (CHAR *)bson_array_alloc(sizeof(CHAR), len); if (WideCharToMultiByte(CP_UTF8, 0, value, -1, out, len, NULL, NULL)) { return out; } else { @@ -438,7 +438,7 @@ _mongoc_sspi_auth_sspi_client_wrap( } outbufSize = wrapBufs[0].cbBuffer + wrapBufs[1].cbBuffer + wrapBufs[2].cbBuffer; - outbuf = (SEC_CHAR *)bson_malloc(sizeof(SEC_CHAR) * outbufSize); + outbuf = (SEC_CHAR *)bson_array_alloc(sizeof(SEC_CHAR), outbufSize); memcpy_s(outbuf, outbufSize, wrapBufs[0].pvBuffer, wrapBufs[0].cbBuffer); memcpy_s( outbuf + wrapBufs[0].cbBuffer, outbufSize - wrapBufs[0].cbBuffer, wrapBufs[1].pvBuffer, wrapBufs[1].cbBuffer); diff --git a/src/libmongoc/src/mongoc/mongoc-stream-socket.c b/src/libmongoc/src/mongoc/mongoc-stream-socket.c index 47a6fc0891..28d228637b 100644 --- a/src/libmongoc/src/mongoc/mongoc-stream-socket.c +++ b/src/libmongoc/src/mongoc/mongoc-stream-socket.c @@ -214,7 +214,7 @@ _mongoc_stream_socket_poll(mongoc_stream_poll_t *streams, size_t nstreams, int32 ENTRY; - sds = (mongoc_socket_poll_t *)bson_malloc(sizeof(*sds) * nstreams); + sds = (mongoc_socket_poll_t *)bson_array_alloc(sizeof(*sds), nstreams); for (size_t i = 0u; i < nstreams; i++) { ss = (mongoc_stream_socket_t *)streams[i].stream; diff --git a/src/libmongoc/src/mongoc/mongoc-stream.c b/src/libmongoc/src/mongoc/mongoc-stream.c index 9497e670e8..cf24a683d4 100644 --- a/src/libmongoc/src/mongoc/mongoc-stream.c +++ b/src/libmongoc/src/mongoc/mongoc-stream.c @@ -335,7 +335,7 @@ mongoc_stream_poll(mongoc_stream_poll_t *streams, size_t nstreams, int32_t timeo ssize_t _mongoc_stream_poll_internal(mongoc_stream_poll_t *streams, size_t nstreams, mlib_timer until) { - mongoc_stream_poll_t *poller = (mongoc_stream_poll_t *)bson_malloc(sizeof(*poller) * nstreams); + mongoc_stream_poll_t *poller = (mongoc_stream_poll_t *)bson_array_alloc(sizeof(*poller), nstreams); int last_type = 0; ssize_t rval = -1; diff --git a/src/libmongoc/src/mongoc/mongoc-topology-background-monitoring.c b/src/libmongoc/src/mongoc/mongoc-topology-background-monitoring.c index 032092fe88..beaa843bd5 100644 --- a/src/libmongoc/src/mongoc/mongoc-topology-background-monitoring.c +++ b/src/libmongoc/src/mongoc/mongoc-topology-background-monitoring.c @@ -183,7 +183,7 @@ _remove_orphaned_server_monitors(mongoc_set_t *server_monitors, mongoc_set_t *se /* Signal shutdown to server monitors no longer in the topology description. */ - server_monitor_ids_to_remove = bson_malloc0(sizeof(uint32_t) * server_monitors->items_len); + server_monitor_ids_to_remove = bson_array_alloc(sizeof(uint32_t), server_monitors->items_len); for (size_t i = 0u; i < server_monitors->items_len; i++) { mongoc_server_monitor_t *server_monitor; uint32_t id; diff --git a/src/libmongoc/src/mongoc/mongoc-topology-description.c b/src/libmongoc/src/mongoc/mongoc-topology-description.c index 629afe2e70..5e7e9b2964 100644 --- a/src/libmongoc/src/mongoc/mongoc-topology-description.c +++ b/src/libmongoc/src/mongoc/mongoc-topology-description.c @@ -798,7 +798,7 @@ mongoc_topology_description_suitable_servers(mongoc_array_t *set, /* OUT */ .topology_type = topology->type, .has_secondary = false, .candidates_len = 0, - .candidates = bson_malloc0(sizeof(mongoc_server_description_t *) * td_servers->items_len), + .candidates = bson_array_alloc(sizeof(mongoc_server_description_t *), td_servers->items_len), }; /* The "effective" read mode is the read mode that we should behave for, and @@ -2370,7 +2370,7 @@ mongoc_topology_description_get_servers(const mongoc_topology_description_t *td, { const mongoc_set_t *const set = mc_tpld_servers_const(BSON_ASSERT_PTR_INLINE(td)); /* enough room for all descriptions, even if some are unknown */ - mongoc_server_description_t **sds = bson_malloc0(sizeof(mongoc_server_description_t *) * set->items_len); + mongoc_server_description_t **sds = bson_array_alloc(sizeof(mongoc_server_description_t *), set->items_len); BSON_ASSERT_PARAM(n); diff --git a/src/libmongoc/src/mongoc/mongoc-topology.c b/src/libmongoc/src/mongoc/mongoc-topology.c index 6f2c117bb0..0656f8dab2 100644 --- a/src/libmongoc/src/mongoc/mongoc-topology.c +++ b/src/libmongoc/src/mongoc/mongoc-topology.c @@ -268,7 +268,7 @@ _mongoc_apply_srv_max_hosts(const mongoc_host_list_t *hl, size_t max_hosts, size return NULL; } - hl_array = bson_malloc(hl_size * sizeof(mongoc_host_list_t *)); + hl_array = bson_array_alloc(sizeof(mongoc_host_list_t *), hl_size); for (size_t idx = 0u; hl; hl = hl->next) { hl_array[idx++] = hl; From cccae5db04d01d0432b863813a60b32b10e8cdf4 Mon Sep 17 00:00:00 2001 From: Julia-Garland Date: Tue, 26 Aug 2025 12:06:12 -0400 Subject: [PATCH 03/13] Use correct alignof macro --- src/libbson/src/bson/memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libbson/src/bson/memory.c b/src/libbson/src/bson/memory.c index be15675073..f40e42e839 100644 --- a/src/libbson/src/bson/memory.c +++ b/src/libbson/src/bson/memory.c @@ -261,7 +261,7 @@ bson_array_alloc(size_t type_size /* IN */, size_t len /* IN */) size_t num_bytes = type_size * len; if (BSON_LIKELY(num_bytes) && BSON_LIKELY(type_size == num_bytes / len)) { - mem = bson_aligned_alloc0(BSON_ALIGN_OF(type_size), num_bytes); + mem = bson_aligned_alloc0(BSON_ALIGNOF(type_size), num_bytes); } return mem; } From b4c8bb876912b483fb7f35e9dd1bdfcbfc511813 Mon Sep 17 00:00:00 2001 From: Julia-Garland Date: Wed, 27 Aug 2025 09:59:29 -0400 Subject: [PATCH 04/13] Split bson_alloc_array into two versions for bson_malloc0 calls; alignment no longer used --- src/libbson/src/bson/memory.c | 50 ++++++++++++++++--- src/libbson/src/bson/memory.h | 4 +- src/libbson/src/jsonsl/jsonsl.c | 2 +- src/libbson/tests/test-bson-vector.c | 6 +-- .../src/mongoc/mongoc-cluster-sspi.c | 6 +-- .../src/mongoc/mongoc-server-description.c | 2 +- .../mongoc-topology-background-monitoring.c | 2 +- .../src/mongoc/mongoc-topology-description.c | 4 +- 8 files changed, 56 insertions(+), 20 deletions(-) diff --git a/src/libbson/src/bson/memory.c b/src/libbson/src/bson/memory.c index f40e42e839..2b7be8276a 100644 --- a/src/libbson/src/bson/memory.c +++ b/src/libbson/src/bson/memory.c @@ -236,13 +236,13 @@ bson_aligned_alloc0(size_t alignment /* IN */, size_t num_bytes /* IN */) * * bson_array_alloc -- * - * Allocates zero-filled, aligned memory for an array of objects, - * checking for cases of n = 0 and integer overflow in type_size * len, - * in which case NULL is returned. + * Allocates memory for an array of objects, checking for cases of + * n = 0 and integer overflow in type_size * len, in which case NULL + * is returned. * * Parameters: * @type_size: The size of each object's type in bytes. - * @len: The number of objects to allocate. + * @num_elems: The number of objects to allocate. * * Returns: * A pointer if successful; otherwise abort() is called and this @@ -255,13 +255,47 @@ bson_aligned_alloc0(size_t alignment /* IN */, size_t num_bytes /* IN */) */ void * -bson_array_alloc(size_t type_size /* IN */, size_t len /* IN */) +bson_array_alloc(size_t type_size /* IN */, size_t num_elems /* IN */) { void *mem = NULL; - size_t num_bytes = type_size * len; + size_t num_bytes = type_size * num_elems; - if (BSON_LIKELY(num_bytes) && BSON_LIKELY(type_size == num_bytes / len)) { - mem = bson_aligned_alloc0(BSON_ALIGNOF(type_size), num_bytes); + if (BSON_LIKELY(num_bytes) && BSON_LIKELY(num_elems == num_bytes / type_size)) { + mem = bson_malloc(num_bytes); + } + return mem; +} + +/* + *-------------------------------------------------------------------------- + * + * bson_array_alloc0 -- + * + * Like bson_array_alloc() except the memory is zeroed after allocation + * for convenience. + * + * Parameters: + * @type_size: The size of each object's type in bytes. + * @num_elems: The number of objects to allocate. + * + * Returns: + * A pointer if successful; otherwise abort() is called and this + * function will never return. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ + + void * +bson_array_alloc0(size_t type_size /* IN */, size_t num_elems /* IN */) +{ + void *mem = NULL; + size_t num_bytes = type_size * num_elems; + + if (BSON_LIKELY(num_bytes) && BSON_LIKELY(num_elems == num_bytes / type_size)) { + mem = bson_malloc0(num_bytes); } return mem; } diff --git a/src/libbson/src/bson/memory.h b/src/libbson/src/bson/memory.h index e13aedfd30..ec06832c26 100644 --- a/src/libbson/src/bson/memory.h +++ b/src/libbson/src/bson/memory.h @@ -48,7 +48,9 @@ bson_aligned_alloc(size_t alignment, size_t num_bytes); BSON_EXPORT(void *) bson_aligned_alloc0(size_t alignment, size_t num_bytes); BSON_EXPORT(void *) -bson_array_alloc(size_t type_size, size_t len); +bson_array_alloc(size_t type_size, size_t num_elems); +BSON_EXPORT(void *) +bson_array_alloc0(size_t type_size, size_t num_elems); BSON_EXPORT(void *) bson_realloc(void *mem, size_t num_bytes); BSON_EXPORT(void *) diff --git a/src/libbson/src/jsonsl/jsonsl.c b/src/libbson/src/jsonsl/jsonsl.c index f71f517abe..2b9514c3bc 100644 --- a/src/libbson/src/jsonsl/jsonsl.c +++ b/src/libbson/src/jsonsl/jsonsl.c @@ -1054,7 +1054,7 @@ void jsonsl_jpr_match_state_init(jsonsl_t jsn, } jsn->jprs = (jsonsl_jpr_t *) bson_array_alloc (sizeof (jsonsl_jpr_t), njprs); jsn->jpr_count = njprs; - jsn->jpr_root = (size_t *) bson_array_alloc (sizeof (size_t), njprs * jsn->levels_max); + jsn->jpr_root = (size_t *) bson_array_alloc0 (sizeof (size_t), njprs * jsn->levels_max); memcpy(jsn->jprs, jprs, sizeof(jsonsl_jpr_t) * njprs); /* Set the initial jump table values */ diff --git a/src/libbson/tests/test-bson-vector.c b/src/libbson/tests/test-bson-vector.c index 6ef4296e05..d360b7f1e6 100644 --- a/src/libbson/tests/test-bson-vector.c +++ b/src/libbson/tests/test-bson-vector.c @@ -1392,7 +1392,7 @@ test_bson_vector_edge_cases_int8(void) // Test some read and write boundaries. { size_t values_size = 100; - int8_t *values = bson_array_alloc(sizeof *values, values_size); + int8_t *values = bson_array_alloc0(sizeof *values, values_size); TEST_BSON_VECTOR_EDGE_CASES_RW_COMMON( view, max_alloc_elements, values, values_size, bson_vector_int8_view_read, bson_vector_int8_view_write); bson_free(values); @@ -1439,7 +1439,7 @@ test_bson_vector_edge_cases_float32(void) // Test some read and write boundaries. { size_t values_size = 100; - float *values = bson_array_alloc(sizeof *values, values_size); + float *values = bson_array_alloc0(sizeof *values, values_size); TEST_BSON_VECTOR_EDGE_CASES_RW_COMMON( view, max_alloc_elements, values, values_size, bson_vector_float32_view_read, bson_vector_float32_view_write); bson_free(values); @@ -1506,7 +1506,7 @@ test_bson_vector_edge_cases_packed_bit(void) // Only tests one length, but it's chosen to be greater than 8 and not a multiple of 8. { size_t values_size = 190; - bool *values = bson_array_alloc(sizeof *values, values_size); + bool *values = bson_array_alloc0(sizeof *values, values_size); TEST_BSON_VECTOR_EDGE_CASES_RW_COMMON(view, max_alloc_elements, values, diff --git a/src/libmongoc/src/mongoc/mongoc-cluster-sspi.c b/src/libmongoc/src/mongoc/mongoc-cluster-sspi.c index 4a260f3b9e..58eafb6a23 100644 --- a/src/libmongoc/src/mongoc/mongoc-cluster-sspi.c +++ b/src/libmongoc/src/mongoc/mongoc-cluster-sspi.c @@ -65,7 +65,7 @@ _mongoc_cluster_sspi_new(mongoc_uri_t *uri, mongoc_stream_t *stream, const char service_ascii_len = strlen(service_ascii); /* this is donated to the sspi */ - service = bson_array_alloc(sizeof(WCHAR), (service_ascii_len + 1)); + service = bson_array_alloc0(sizeof(WCHAR), (service_ascii_len + 1)); service_len = MultiByteToWideChar(CP_UTF8, 0, service_ascii, (int)service_ascii_len, service, (int)service_ascii_len); service[service_len] = L'\0'; @@ -75,7 +75,7 @@ _mongoc_cluster_sspi_new(mongoc_uri_t *uri, mongoc_stream_t *stream, const char tmp_creds_len = strlen(state->sasl.pass); /* this is donated to the sspi */ - pass = bson_array_alloc(sizeof(WCHAR), (tmp_creds_len + 1)); + pass = bson_array_alloc0(sizeof(WCHAR), (tmp_creds_len + 1)); pass_len = MultiByteToWideChar(CP_UTF8, 0, state->sasl.pass, (int)tmp_creds_len, pass, (int)tmp_creds_len); pass[pass_len] = L'\0'; } @@ -84,7 +84,7 @@ _mongoc_cluster_sspi_new(mongoc_uri_t *uri, mongoc_stream_t *stream, const char tmp_creds_len = strlen(state->sasl.user); /* this is donated to the sspi */ - user = bson_array_alloc(sizeof(WCHAR), (tmp_creds_len + 1)); + user = bson_array_alloc0(sizeof(WCHAR), (tmp_creds_len + 1)); user_len = MultiByteToWideChar(CP_UTF8, 0, state->sasl.user, (int)tmp_creds_len, user, (int)tmp_creds_len); user[user_len] = L'\0'; } diff --git a/src/libmongoc/src/mongoc/mongoc-server-description.c b/src/libmongoc/src/mongoc/mongoc-server-description.c index da07c3d29c..ca56ceb5f9 100644 --- a/src/libmongoc/src/mongoc/mongoc-server-description.c +++ b/src/libmongoc/src/mongoc/mongoc-server-description.c @@ -987,7 +987,7 @@ mongoc_server_description_filter_tags(const mongoc_server_description_t **descri return; } - sd_matched = (bool *)bson_array_alloc(sizeof(bool), description_len); + sd_matched = (bool *)bson_array_alloc0(sizeof(bool), description_len); bson_iter_init(&rp_tagset_iter, rp_tags); diff --git a/src/libmongoc/src/mongoc/mongoc-topology-background-monitoring.c b/src/libmongoc/src/mongoc/mongoc-topology-background-monitoring.c index beaa843bd5..2eb75d19f3 100644 --- a/src/libmongoc/src/mongoc/mongoc-topology-background-monitoring.c +++ b/src/libmongoc/src/mongoc/mongoc-topology-background-monitoring.c @@ -183,7 +183,7 @@ _remove_orphaned_server_monitors(mongoc_set_t *server_monitors, mongoc_set_t *se /* Signal shutdown to server monitors no longer in the topology description. */ - server_monitor_ids_to_remove = bson_array_alloc(sizeof(uint32_t), server_monitors->items_len); + server_monitor_ids_to_remove = bson_array_alloc0(sizeof(uint32_t), server_monitors->items_len); for (size_t i = 0u; i < server_monitors->items_len; i++) { mongoc_server_monitor_t *server_monitor; uint32_t id; diff --git a/src/libmongoc/src/mongoc/mongoc-topology-description.c b/src/libmongoc/src/mongoc/mongoc-topology-description.c index 5e7e9b2964..896391942f 100644 --- a/src/libmongoc/src/mongoc/mongoc-topology-description.c +++ b/src/libmongoc/src/mongoc/mongoc-topology-description.c @@ -798,7 +798,7 @@ mongoc_topology_description_suitable_servers(mongoc_array_t *set, /* OUT */ .topology_type = topology->type, .has_secondary = false, .candidates_len = 0, - .candidates = bson_array_alloc(sizeof(mongoc_server_description_t *), td_servers->items_len), + .candidates = bson_array_alloc0(sizeof(mongoc_server_description_t *), td_servers->items_len), }; /* The "effective" read mode is the read mode that we should behave for, and @@ -2370,7 +2370,7 @@ mongoc_topology_description_get_servers(const mongoc_topology_description_t *td, { const mongoc_set_t *const set = mc_tpld_servers_const(BSON_ASSERT_PTR_INLINE(td)); /* enough room for all descriptions, even if some are unknown */ - mongoc_server_description_t **sds = bson_array_alloc(sizeof(mongoc_server_description_t *), set->items_len); + mongoc_server_description_t **sds = bson_array_alloc0(sizeof(mongoc_server_description_t *), set->items_len); BSON_ASSERT_PARAM(n); From 34fa1596289ca0db9891aa520a708675b81924da Mon Sep 17 00:00:00 2001 From: Julia-Garland Date: Wed, 27 Aug 2025 11:30:58 -0400 Subject: [PATCH 05/13] Fix incorrect call --- src/common/src/common-bson-dsl-private.h | 2 +- src/libbson/src/bson/memory.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/common/src/common-bson-dsl-private.h b/src/common/src/common-bson-dsl-private.h index 4adcc6729e..7c688816f7 100644 --- a/src/common/src/common-bson-dsl-private.h +++ b/src/common/src/common-bson-dsl-private.h @@ -666,7 +666,7 @@ BSON_IF_GNU_LIKE(_Pragma("GCC diagnostic ignored \"-Wshadow\"")) while (nth_int >= _bpNumVisitBitInts) { \ /* Say that five times, fast: */ \ size_t new_num_visit_bit_ints = _bpNumVisitBitInts * 2u; \ - uint64_t *new_visit_bit_ints = bson_array_alloc(sizeof(uint64_t), new_num_visit_bit_ints); \ + uint64_t *new_visit_bit_ints = bson_array_alloc0(sizeof(uint64_t), new_num_visit_bit_ints); \ memcpy(new_visit_bit_ints, _bpVisitBits, sizeof(uint64_t) * _bpNumVisitBitInts); \ if (_bpVisitBits != _bpVisitBits_static) { \ bson_free(_bpVisitBits); \ diff --git a/src/libbson/src/bson/memory.c b/src/libbson/src/bson/memory.c index 2b7be8276a..6a4707fdfb 100644 --- a/src/libbson/src/bson/memory.c +++ b/src/libbson/src/bson/memory.c @@ -236,8 +236,8 @@ bson_aligned_alloc0(size_t alignment /* IN */, size_t num_bytes /* IN */) * * bson_array_alloc -- * - * Allocates memory for an array of objects, checking for cases of - * n = 0 and integer overflow in type_size * len, in which case NULL + * Allocates memory for an array of objects, checking for cases of + * n = 0 and integer overflow in type_size * len, in which case NULL * is returned. * * Parameters: @@ -288,7 +288,7 @@ bson_array_alloc(size_t type_size /* IN */, size_t num_elems /* IN */) *-------------------------------------------------------------------------- */ - void * +void * bson_array_alloc0(size_t type_size /* IN */, size_t num_elems /* IN */) { void *mem = NULL; From de6fd910847a23e59979ca2c8d2ee9dc8fd22612 Mon Sep 17 00:00:00 2001 From: Julia-Garland Date: Wed, 27 Aug 2025 12:16:25 -0400 Subject: [PATCH 06/13] Create docs page for bson_alloc_array(0) --- src/common/src/common-bson-dsl-private.h | 34 +++++++++++----------- src/libbson/doc/bson_alloc_array.rst | 36 ++++++++++++++++++++++++ src/libbson/doc/bson_alloc_array0.rst | 36 ++++++++++++++++++++++++ src/libbson/doc/bson_memory.rst | 2 ++ 4 files changed, 91 insertions(+), 17 deletions(-) create mode 100644 src/libbson/doc/bson_alloc_array.rst create mode 100644 src/libbson/doc/bson_alloc_array0.rst diff --git a/src/common/src/common-bson-dsl-private.h b/src/common/src/common-bson-dsl-private.h index 7c688816f7..dc028df597 100644 --- a/src/common/src/common-bson-dsl-private.h +++ b/src/common/src/common-bson-dsl-private.h @@ -659,24 +659,24 @@ BSON_IF_GNU_LIKE(_Pragma("GCC diagnostic ignored \"-Wshadow\"")) } \ } while (0); -#define _bsonParseMarkVisited(Index) \ - if (1) { \ - const size_t nth_int = Index / 64u; \ - const size_t nth_bit = Index % 64u; \ - while (nth_int >= _bpNumVisitBitInts) { \ - /* Say that five times, fast: */ \ - size_t new_num_visit_bit_ints = _bpNumVisitBitInts * 2u; \ +#define _bsonParseMarkVisited(Index) \ + if (1) { \ + const size_t nth_int = Index / 64u; \ + const size_t nth_bit = Index % 64u; \ + while (nth_int >= _bpNumVisitBitInts) { \ + /* Say that five times, fast: */ \ + size_t new_num_visit_bit_ints = _bpNumVisitBitInts * 2u; \ uint64_t *new_visit_bit_ints = bson_array_alloc0(sizeof(uint64_t), new_num_visit_bit_ints); \ - memcpy(new_visit_bit_ints, _bpVisitBits, sizeof(uint64_t) * _bpNumVisitBitInts); \ - if (_bpVisitBits != _bpVisitBits_static) { \ - bson_free(_bpVisitBits); \ - } \ - _bpVisitBits = new_visit_bit_ints; \ - _bpNumVisitBitInts = new_num_visit_bit_ints; \ - } \ - \ - _bpVisitBits[nth_int] |= (UINT64_C(1) << nth_bit); \ - } else \ + memcpy(new_visit_bit_ints, _bpVisitBits, sizeof(uint64_t) * _bpNumVisitBitInts); \ + if (_bpVisitBits != _bpVisitBits_static) { \ + bson_free(_bpVisitBits); \ + } \ + _bpVisitBits = new_visit_bit_ints; \ + _bpNumVisitBitInts = new_num_visit_bit_ints; \ + } \ + \ + _bpVisitBits[nth_int] |= (UINT64_C(1) << nth_bit); \ + } else \ ((void)0) #define _bsonParseDidVisitNth(Index) _bsonParseDidVisitNth_1(Index / 64u, Index % 64u) diff --git a/src/libbson/doc/bson_alloc_array.rst b/src/libbson/doc/bson_alloc_array.rst new file mode 100644 index 0000000000..4425aa0ff8 --- /dev/null +++ b/src/libbson/doc/bson_alloc_array.rst @@ -0,0 +1,36 @@ +:man_page: bson_alloc_array + +bson_alloc_array() +============= + +Synopsis +-------- + +.. code-block:: c + + void * + bson_alloc_array (size_t type_size, size_t num_elems); + +Parameters +---------- + +* ``type_size``: A size_t containing the size in bytes of a single object in the array. +* ``num_elems``: A size_t containing the number of objects to be stored in the array. + +Description +----------- + +This is a portable ``malloc()`` wrapper to allocate an array of objects. + +In general, this function will return an allocation at least ``sizeof(void*)`` bytes or bigger. + +If there was a failure to allocate ``type_size * num_elems`` bytes, the process will be aborted. + +.. warning:: + + This function will abort on failure to allocate memory. + +Returns +------- + +A pointer to a memory region which *HAS NOT* been zeroed. \ No newline at end of file diff --git a/src/libbson/doc/bson_alloc_array0.rst b/src/libbson/doc/bson_alloc_array0.rst new file mode 100644 index 0000000000..8fd8385fb9 --- /dev/null +++ b/src/libbson/doc/bson_alloc_array0.rst @@ -0,0 +1,36 @@ +:man_page: bson_alloc_array0 + +bson_alloc_array0() +============= + +Synopsis +-------- + +.. code-block:: c + + void * + bson_alloc_array0 (size_t type_size, size_t num_elems); + +Parameters +---------- + +* ``type_size``: A size_t containing the size in bytes of a single object in the array. +* ``num_elems``: A size_t containing the number of objects to be stored in the array. + +Description +----------- + +This is a portable ``malloc()`` wrapper to allocate an array of objects that also sets the memory to zero. + +In general, this function will return an allocation at least ``sizeof(void*)`` bytes or bigger. + +If there was a failure to allocate ``type_size * num_elems`` bytes, the process will be aborted. + +.. warning:: + + This function will abort on failure to allocate memory. + +Returns +------- + +A pointer to a memory region which *HAS* been zeroed. \ No newline at end of file diff --git a/src/libbson/doc/bson_memory.rst b/src/libbson/doc/bson_memory.rst index 24eb1c9095..69d84757b8 100644 --- a/src/libbson/doc/bson_memory.rst +++ b/src/libbson/doc/bson_memory.rst @@ -26,6 +26,8 @@ To aid in language binding integration, Libbson allows for setting a custom memo bson_malloc0 bson_aligned_alloc bson_aligned_alloc0 + bson_array_alloc + bson_array_alloc0 bson_mem_restore_vtable bson_mem_set_vtable bson_realloc From 1a955ac12b93b8dfc3a921bb038d2c540edf2890 Mon Sep 17 00:00:00 2001 From: Julia-Garland Date: Wed, 27 Aug 2025 12:48:09 -0400 Subject: [PATCH 07/13] Extend title underline --- src/libbson/doc/bson_alloc_array.rst | 2 +- src/libbson/doc/bson_alloc_array0.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libbson/doc/bson_alloc_array.rst b/src/libbson/doc/bson_alloc_array.rst index 4425aa0ff8..d582cd1699 100644 --- a/src/libbson/doc/bson_alloc_array.rst +++ b/src/libbson/doc/bson_alloc_array.rst @@ -1,7 +1,7 @@ :man_page: bson_alloc_array bson_alloc_array() -============= +================== Synopsis -------- diff --git a/src/libbson/doc/bson_alloc_array0.rst b/src/libbson/doc/bson_alloc_array0.rst index 8fd8385fb9..9043d58707 100644 --- a/src/libbson/doc/bson_alloc_array0.rst +++ b/src/libbson/doc/bson_alloc_array0.rst @@ -1,7 +1,7 @@ :man_page: bson_alloc_array0 bson_alloc_array0() -============= +=================== Synopsis -------- From fcd73e6ca903895050e14930bfa8b7fcb7859626 Mon Sep 17 00:00:00 2001 From: Julia-Garland Date: Wed, 27 Aug 2025 13:31:12 -0400 Subject: [PATCH 08/13] Fix function name in docs --- .../doc/{bson_alloc_array.rst => bson_array_alloc.rst} | 6 +++--- .../doc/{bson_alloc_array0.rst => bson_array_alloc0.rst} | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) rename src/libbson/doc/{bson_alloc_array.rst => bson_array_alloc.rst} (87%) rename src/libbson/doc/{bson_alloc_array0.rst => bson_array_alloc0.rst} (87%) diff --git a/src/libbson/doc/bson_alloc_array.rst b/src/libbson/doc/bson_array_alloc.rst similarity index 87% rename from src/libbson/doc/bson_alloc_array.rst rename to src/libbson/doc/bson_array_alloc.rst index d582cd1699..03ceb53786 100644 --- a/src/libbson/doc/bson_alloc_array.rst +++ b/src/libbson/doc/bson_array_alloc.rst @@ -1,6 +1,6 @@ -:man_page: bson_alloc_array +:man_page: bson_array_alloc -bson_alloc_array() +bson_array_alloc() ================== Synopsis @@ -9,7 +9,7 @@ Synopsis .. code-block:: c void * - bson_alloc_array (size_t type_size, size_t num_elems); + bson_array_alloc (size_t type_size, size_t num_elems); Parameters ---------- diff --git a/src/libbson/doc/bson_alloc_array0.rst b/src/libbson/doc/bson_array_alloc0.rst similarity index 87% rename from src/libbson/doc/bson_alloc_array0.rst rename to src/libbson/doc/bson_array_alloc0.rst index 9043d58707..20111ef485 100644 --- a/src/libbson/doc/bson_alloc_array0.rst +++ b/src/libbson/doc/bson_array_alloc0.rst @@ -1,6 +1,6 @@ -:man_page: bson_alloc_array0 +:man_page: bson_array_alloc0 -bson_alloc_array0() +bson_array_alloc0() =================== Synopsis @@ -9,7 +9,7 @@ Synopsis .. code-block:: c void * - bson_alloc_array0 (size_t type_size, size_t num_elems); + bson_array_alloc0 (size_t type_size, size_t num_elems); Parameters ---------- From cbe412eb21e337ad4e11009a86b148d153e71f62 Mon Sep 17 00:00:00 2001 From: Julia-Garland Date: Wed, 3 Sep 2025 11:42:08 -0400 Subject: [PATCH 09/13] Add a BSON_ARRAY_ALLOC macro to handle casting from void* --- src/common/src/common-bson-dsl-private.h | 36 ++++++++--------- src/libbson/doc/bson_array_alloc.rst | 11 ++++-- src/libbson/doc/bson_array_alloc0.rst | 13 ++++--- src/libbson/src/bson/memory.c | 39 ++++++++++--------- src/libbson/src/bson/memory.h | 6 ++- src/libbson/src/jsonsl/jsonsl.c | 4 +- src/libbson/tests/test-bson-vector.c | 18 ++++----- src/libmongoc/src/mongoc/mcd-rpc.c | 2 +- src/libmongoc/src/mongoc/mongoc-async-cmd.c | 2 +- .../mongoc/mongoc-client-side-encryption.c | 4 +- .../src/mongoc/mongoc-cluster-sspi.c | 8 ++-- src/libmongoc/src/mongoc/mongoc-scram.c | 4 +- .../src/mongoc/mongoc-secure-channel.c | 2 +- .../src/mongoc/mongoc-server-description.c | 2 +- src/libmongoc/src/mongoc/mongoc-set.c | 6 +-- src/libmongoc/src/mongoc/mongoc-socket.c | 4 +- src/libmongoc/src/mongoc/mongoc-sspi.c | 8 ++-- .../src/mongoc/mongoc-stream-socket.c | 2 +- src/libmongoc/src/mongoc/mongoc-stream.c | 2 +- .../mongoc-topology-background-monitoring.c | 2 +- .../src/mongoc/mongoc-topology-description.c | 4 +- src/libmongoc/src/mongoc/mongoc-topology.c | 2 +- 22 files changed, 96 insertions(+), 85 deletions(-) diff --git a/src/common/src/common-bson-dsl-private.h b/src/common/src/common-bson-dsl-private.h index dc028df597..18b39936c4 100644 --- a/src/common/src/common-bson-dsl-private.h +++ b/src/common/src/common-bson-dsl-private.h @@ -659,24 +659,24 @@ BSON_IF_GNU_LIKE(_Pragma("GCC diagnostic ignored \"-Wshadow\"")) } \ } while (0); -#define _bsonParseMarkVisited(Index) \ - if (1) { \ - const size_t nth_int = Index / 64u; \ - const size_t nth_bit = Index % 64u; \ - while (nth_int >= _bpNumVisitBitInts) { \ - /* Say that five times, fast: */ \ - size_t new_num_visit_bit_ints = _bpNumVisitBitInts * 2u; \ - uint64_t *new_visit_bit_ints = bson_array_alloc0(sizeof(uint64_t), new_num_visit_bit_ints); \ - memcpy(new_visit_bit_ints, _bpVisitBits, sizeof(uint64_t) * _bpNumVisitBitInts); \ - if (_bpVisitBits != _bpVisitBits_static) { \ - bson_free(_bpVisitBits); \ - } \ - _bpVisitBits = new_visit_bit_ints; \ - _bpNumVisitBitInts = new_num_visit_bit_ints; \ - } \ - \ - _bpVisitBits[nth_int] |= (UINT64_C(1) << nth_bit); \ - } else \ +#define _bsonParseMarkVisited(Index) \ + if (1) { \ + const size_t nth_int = Index / 64u; \ + const size_t nth_bit = Index % 64u; \ + while (nth_int >= _bpNumVisitBitInts) { \ + /* Say that five times, fast: */ \ + size_t new_num_visit_bit_ints = _bpNumVisitBitInts * 2u; \ + uint64_t *new_visit_bit_ints = BSON_ARRAY_ALLOC0(new_num_visit_bit_ints, uint64_t); \ + memcpy(new_visit_bit_ints, _bpVisitBits, sizeof(uint64_t) * _bpNumVisitBitInts); \ + if (_bpVisitBits != _bpVisitBits_static) { \ + bson_free(_bpVisitBits); \ + } \ + _bpVisitBits = new_visit_bit_ints; \ + _bpNumVisitBitInts = new_num_visit_bit_ints; \ + } \ + \ + _bpVisitBits[nth_int] |= (UINT64_C(1) << nth_bit); \ + } else \ ((void)0) #define _bsonParseDidVisitNth(Index) _bsonParseDidVisitNth_1(Index / 64u, Index % 64u) diff --git a/src/libbson/doc/bson_array_alloc.rst b/src/libbson/doc/bson_array_alloc.rst index 03ceb53786..f3f17db9fb 100644 --- a/src/libbson/doc/bson_array_alloc.rst +++ b/src/libbson/doc/bson_array_alloc.rst @@ -8,14 +8,17 @@ Synopsis .. code-block:: c + #define BSON_ARRAY_ALLOC(Count, Type) \ + (Type*) bson_array_alloc (Count, sizeof (Type)) + void * - bson_array_alloc (size_t type_size, size_t num_elems); + bson_array_alloc (size_t num_elems, size_t elem_size); Parameters ---------- -* ``type_size``: A size_t containing the size in bytes of a single object in the array. -* ``num_elems``: A size_t containing the number of objects to be stored in the array. +* ``num_elems``: A size_t containing the number of objects to allocate. +* ``elem_size``: A size_t containing the size of each object in bytes. Description ----------- @@ -24,7 +27,7 @@ This is a portable ``malloc()`` wrapper to allocate an array of objects. In general, this function will return an allocation at least ``sizeof(void*)`` bytes or bigger. -If there was a failure to allocate ``type_size * num_elems`` bytes, the process will be aborted. +If there was a failure to allocate ``num_elems * elem_size`` bytes, the process will be aborted. .. warning:: diff --git a/src/libbson/doc/bson_array_alloc0.rst b/src/libbson/doc/bson_array_alloc0.rst index 20111ef485..91f5f22b52 100644 --- a/src/libbson/doc/bson_array_alloc0.rst +++ b/src/libbson/doc/bson_array_alloc0.rst @@ -8,23 +8,26 @@ Synopsis .. code-block:: c + #define BSON_ARRAY_ALLOC0(Count, Type) \ + (Type*) bson_array_alloc0 (Count, sizeof (Type)) + void * - bson_array_alloc0 (size_t type_size, size_t num_elems); + bson_array_alloc0 (size_t num_elems, size_t elem_size); Parameters ---------- -* ``type_size``: A size_t containing the size in bytes of a single object in the array. -* ``num_elems``: A size_t containing the number of objects to be stored in the array. +* ``num_elems``: A size_t containing the number of objects to allocate. +* ``elem_size``: A size_t containing the size of each object in bytes. Description ----------- -This is a portable ``malloc()`` wrapper to allocate an array of objects that also sets the memory to zero. +This is a portable ``calloc()`` wrapper to allocate an array of objects that also sets the memory to zero. In general, this function will return an allocation at least ``sizeof(void*)`` bytes or bigger. -If there was a failure to allocate ``type_size * num_elems`` bytes, the process will be aborted. +If there was a failure to allocate ``num_elems * elem_size`` bytes, the process will be aborted. .. warning:: diff --git a/src/libbson/src/bson/memory.c b/src/libbson/src/bson/memory.c index 6a4707fdfb..b3240f8fae 100644 --- a/src/libbson/src/bson/memory.c +++ b/src/libbson/src/bson/memory.c @@ -236,31 +236,30 @@ bson_aligned_alloc0(size_t alignment /* IN */, size_t num_bytes /* IN */) * * bson_array_alloc -- * - * Allocates memory for an array of objects, checking for cases of - * n = 0 and integer overflow in type_size * len, in which case NULL - * is returned. + * Allocates memory for an array of objects. + * + * Libbson does not try to handle OOM conditions as it is beyond the + * scope of this library to handle so appropriately. * * Parameters: - * @type_size: The size of each object's type in bytes. * @num_elems: The number of objects to allocate. + * @elem_size: The size of each object in bytes. * * Returns: * A pointer if successful; otherwise abort() is called and this - * function will never return. - * - * Side effects: - * None. + * function will never return. In the cases of num_elems = 0 or + * integer overflow in num_elems * elem_size, NULL is returned. * *-------------------------------------------------------------------------- */ void * -bson_array_alloc(size_t type_size /* IN */, size_t num_elems /* IN */) +bson_array_alloc(size_t num_elems /* IN */, size_t elem_size /* IN */) { void *mem = NULL; - size_t num_bytes = type_size * num_elems; + size_t num_bytes = num_elems * elem_size; - if (BSON_LIKELY(num_bytes) && BSON_LIKELY(num_elems == num_bytes / type_size)) { + if (BSON_LIKELY(num_bytes) && BSON_LIKELY(num_elems == num_bytes / elem_size)) { mem = bson_malloc(num_bytes); } return mem; @@ -269,18 +268,19 @@ bson_array_alloc(size_t type_size /* IN */, size_t num_elems /* IN */) /* *-------------------------------------------------------------------------- * - * bson_array_alloc0 -- + * bson_array_alloc0-- * * Like bson_array_alloc() except the memory is zeroed after allocation * for convenience. * * Parameters: - * @type_size: The size of each object's type in bytes. * @num_elems: The number of objects to allocate. + * @elem_size: The size of each object in bytes. * * Returns: * A pointer if successful; otherwise abort() is called and this - * function will never return. + * function will never return. In the cases of num_elems = 0 or + * integer overflow in num_elems * elem_size, NULL is returned. * * Side effects: * None. @@ -289,13 +289,16 @@ bson_array_alloc(size_t type_size /* IN */, size_t num_elems /* IN */) */ void * -bson_array_alloc0(size_t type_size /* IN */, size_t num_elems /* IN */) +bson_array_alloc0(size_t num_elems /* IN */, size_t elem_size /* IN */) { void *mem = NULL; - size_t num_bytes = type_size * num_elems; + size_t num_bytes = num_elems * elem_size; - if (BSON_LIKELY(num_bytes) && BSON_LIKELY(num_elems == num_bytes / type_size)) { - mem = bson_malloc0(num_bytes); + if (BSON_LIKELY(num_bytes) && BSON_LIKELY(num_elems == num_bytes / elem_size)) { + if (BSON_UNLIKELY(!(mem = gMemVtable.calloc(num_elems, elem_size)))) { + fprintf(stderr, "Failure to allocate memory in bson_array_alloc0(). errno: %d.\n", errno); + abort(); + } } return mem; } diff --git a/src/libbson/src/bson/memory.h b/src/libbson/src/bson/memory.h index ec06832c26..1c8fc5f48e 100644 --- a/src/libbson/src/bson/memory.h +++ b/src/libbson/src/bson/memory.h @@ -48,9 +48,9 @@ bson_aligned_alloc(size_t alignment, size_t num_bytes); BSON_EXPORT(void *) bson_aligned_alloc0(size_t alignment, size_t num_bytes); BSON_EXPORT(void *) -bson_array_alloc(size_t type_size, size_t num_elems); +bson_array_alloc(size_t num_elems, size_t elem_size); BSON_EXPORT(void *) -bson_array_alloc0(size_t type_size, size_t num_elems); +bson_array_alloc0(size_t num_elems, size_t elem_size); BSON_EXPORT(void *) bson_realloc(void *mem, size_t num_bytes); BSON_EXPORT(void *) @@ -63,6 +63,8 @@ bson_zero_free(void *mem, size_t size); #define BSON_ALIGNED_ALLOC(T) ((T *)(bson_aligned_alloc(BSON_ALIGNOF(T), sizeof(T)))) #define BSON_ALIGNED_ALLOC0(T) ((T *)(bson_aligned_alloc0(BSON_ALIGNOF(T), sizeof(T)))) +#define BSON_ARRAY_ALLOC(N, T) ((T *)(bson_array_alloc(N, sizeof(T)))) +#define BSON_ARRAY_ALLOC0(N, T) ((T *)(bson_array_alloc0(N, sizeof(T)))) BSON_END_DECLS diff --git a/src/libbson/src/jsonsl/jsonsl.c b/src/libbson/src/jsonsl/jsonsl.c index 2b9514c3bc..92e6b73125 100644 --- a/src/libbson/src/jsonsl/jsonsl.c +++ b/src/libbson/src/jsonsl/jsonsl.c @@ -1052,9 +1052,9 @@ void jsonsl_jpr_match_state_init(jsonsl_t jsn, if (njprs == 0) { return; } - jsn->jprs = (jsonsl_jpr_t *) bson_array_alloc (sizeof (jsonsl_jpr_t), njprs); + jsn->jprs = BSON_ARRAY_ALLOC(njprs, jsonsl_jpr_t); jsn->jpr_count = njprs; - jsn->jpr_root = (size_t *) bson_array_alloc0 (sizeof (size_t), njprs * jsn->levels_max); + jsn->jpr_root = BSON_ARRAY_ALLOC0(njprs * jsn->levels_max, size_t); memcpy(jsn->jprs, jprs, sizeof(jsonsl_jpr_t) * njprs); /* Set the initial jump table values */ diff --git a/src/libbson/tests/test-bson-vector.c b/src/libbson/tests/test-bson-vector.c index d360b7f1e6..6c1202bda2 100644 --- a/src/libbson/tests/test-bson-vector.c +++ b/src/libbson/tests/test-bson-vector.c @@ -920,8 +920,8 @@ test_bson_vector_view_api_fuzz_int8(void) { size_t current_length = 0; bson_t vector_doc = BSON_INITIALIZER; - int8_t *expected_elements = bson_array_alloc(sizeof *expected_elements, MAX_TESTED_VECTOR_LENGTH); - int8_t *actual_elements = bson_array_alloc(sizeof *actual_elements, MAX_TESTED_VECTOR_LENGTH); + int8_t *expected_elements = BSON_ARRAY_ALLOC(MAX_TESTED_VECTOR_LENGTH, int8_t); + int8_t *actual_elements = BSON_ARRAY_ALLOC(MAX_TESTED_VECTOR_LENGTH, int8_t); for (int fuzz_iter = 0; fuzz_iter < FUZZ_TEST_ITERS; fuzz_iter++) { unsigned r = (unsigned)rand(); unsigned r_operation = r & 0xFu; @@ -974,8 +974,8 @@ test_bson_vector_view_api_fuzz_float32(void) { size_t current_length = 0; bson_t vector_doc = BSON_INITIALIZER; - float *expected_elements = bson_array_alloc(sizeof *expected_elements, MAX_TESTED_VECTOR_LENGTH); - float *actual_elements = bson_array_alloc(sizeof *actual_elements, MAX_TESTED_VECTOR_LENGTH); + float *expected_elements = BSON_ARRAY_ALLOC(MAX_TESTED_VECTOR_LENGTH, float); + float *actual_elements = BSON_ARRAY_ALLOC(MAX_TESTED_VECTOR_LENGTH, float); for (int fuzz_iter = 0; fuzz_iter < FUZZ_TEST_ITERS; fuzz_iter++) { unsigned r = (unsigned)rand(); unsigned r_operation = r & 0xFu; @@ -1028,8 +1028,8 @@ test_bson_vector_view_api_fuzz_packed_bit(void) { size_t current_length = 0; bson_t vector_doc = BSON_INITIALIZER; - bool *expected_elements = bson_array_alloc(sizeof *expected_elements, MAX_TESTED_VECTOR_LENGTH); - bool *actual_elements = bson_array_alloc(sizeof *actual_elements, MAX_TESTED_VECTOR_LENGTH); + bool *expected_elements = BSON_ARRAY_ALLOC(MAX_TESTED_VECTOR_LENGTH, bool); + bool *actual_elements = BSON_ARRAY_ALLOC(MAX_TESTED_VECTOR_LENGTH, bool); uint8_t *packed_buffer = bson_malloc((MAX_TESTED_VECTOR_LENGTH + 7) / 8); for (int fuzz_iter = 0; fuzz_iter < FUZZ_TEST_ITERS; fuzz_iter++) { unsigned r = (unsigned)rand(); @@ -1392,7 +1392,7 @@ test_bson_vector_edge_cases_int8(void) // Test some read and write boundaries. { size_t values_size = 100; - int8_t *values = bson_array_alloc0(sizeof *values, values_size); + int8_t *values = BSON_ARRAY_ALLOC0(values_size, int8_t); TEST_BSON_VECTOR_EDGE_CASES_RW_COMMON( view, max_alloc_elements, values, values_size, bson_vector_int8_view_read, bson_vector_int8_view_write); bson_free(values); @@ -1439,7 +1439,7 @@ test_bson_vector_edge_cases_float32(void) // Test some read and write boundaries. { size_t values_size = 100; - float *values = bson_array_alloc0(sizeof *values, values_size); + float *values = BSON_ARRAY_ALLOC0(values_size, float); TEST_BSON_VECTOR_EDGE_CASES_RW_COMMON( view, max_alloc_elements, values, values_size, bson_vector_float32_view_read, bson_vector_float32_view_write); bson_free(values); @@ -1506,7 +1506,7 @@ test_bson_vector_edge_cases_packed_bit(void) // Only tests one length, but it's chosen to be greater than 8 and not a multiple of 8. { size_t values_size = 190; - bool *values = bson_array_alloc0(sizeof *values, values_size); + bool *values = BSON_ARRAY_ALLOC0(values_size, bool); TEST_BSON_VECTOR_EDGE_CASES_RW_COMMON(view, max_alloc_elements, values, diff --git a/src/libmongoc/src/mongoc/mcd-rpc.c b/src/libmongoc/src/mongoc/mcd-rpc.c index 4832fb5cc5..dbf5af0ae0 100644 --- a/src/libmongoc/src/mongoc/mcd-rpc.c +++ b/src/libmongoc/src/mongoc/mcd-rpc.c @@ -957,7 +957,7 @@ _append_iovec_reserve_space_for(mongoc_iovec_t **iovecs, BSON_ASSERT(*capacity == 4u); *capacity += additional_capacity; - *iovecs = bson_array_alloc(sizeof(mongoc_iovec_t), *capacity); + *iovecs = BSON_ARRAY_ALLOC(*capacity, mongoc_iovec_t); memcpy(*iovecs, header_iovecs, 4u * sizeof(mongoc_iovec_t)); } diff --git a/src/libmongoc/src/mongoc/mongoc-async-cmd.c b/src/libmongoc/src/mongoc/mongoc-async-cmd.c index ad55a09e1d..3ca7acbb16 100644 --- a/src/libmongoc/src/mongoc/mongoc-async-cmd.c +++ b/src/libmongoc/src/mongoc/mongoc-async-cmd.c @@ -339,7 +339,7 @@ _mongoc_async_cmd_phase_send(mongoc_async_cmd_t *acmd) /* create a new iovec with the remaining data to be written. */ niovec = acmd->niovec - i; - iovec = bson_array_alloc(sizeof(mongoc_iovec_t), niovec); + iovec = BSON_ARRAY_ALLOC(niovec, mongoc_iovec_t); memcpy(iovec, acmd->iovec + i, niovec * sizeof(mongoc_iovec_t)); iovec[0].iov_base = (char *)iovec[0].iov_base + offset; iovec[0].iov_len -= offset; diff --git a/src/libmongoc/src/mongoc/mongoc-client-side-encryption.c b/src/libmongoc/src/mongoc/mongoc-client-side-encryption.c index eff49d5cc9..27f5b145da 100644 --- a/src/libmongoc/src/mongoc/mongoc-client-side-encryption.c +++ b/src/libmongoc/src/mongoc/mongoc-client-side-encryption.c @@ -409,7 +409,7 @@ mongoc_client_encryption_datakey_opts_set_keyaltnames(mongoc_client_encryption_d BSON_ASSERT(!opts->keyaltnames); if (keyaltnames_count) { - opts->keyaltnames = bson_array_alloc(sizeof(char *), keyaltnames_count); + opts->keyaltnames = BSON_ARRAY_ALLOC(keyaltnames_count, char *); for (uint32_t i = 0u; i < keyaltnames_count; i++) { opts->keyaltnames[i] = bson_strdup(keyaltnames[i]); } @@ -1601,7 +1601,7 @@ _spawn_mongocryptd(const char *mongocryptd_spawn_path, const bson_t *mongocryptd num_args++; } - args = (char **)bson_array_alloc(sizeof(char *), num_args); + args = BSON_ARRAY_ALLOC(num_args, char *); i = 0; args[i++] = "mongocryptd"; diff --git a/src/libmongoc/src/mongoc/mongoc-cluster-sspi.c b/src/libmongoc/src/mongoc/mongoc-cluster-sspi.c index 58eafb6a23..33a0bdfcf1 100644 --- a/src/libmongoc/src/mongoc/mongoc-cluster-sspi.c +++ b/src/libmongoc/src/mongoc/mongoc-cluster-sspi.c @@ -65,7 +65,7 @@ _mongoc_cluster_sspi_new(mongoc_uri_t *uri, mongoc_stream_t *stream, const char service_ascii_len = strlen(service_ascii); /* this is donated to the sspi */ - service = bson_array_alloc0(sizeof(WCHAR), (service_ascii_len + 1)); + service = BSON_ARRAY_ALLOC0((service_ascii_len + 1), WCHAR); service_len = MultiByteToWideChar(CP_UTF8, 0, service_ascii, (int)service_ascii_len, service, (int)service_ascii_len); service[service_len] = L'\0'; @@ -75,7 +75,7 @@ _mongoc_cluster_sspi_new(mongoc_uri_t *uri, mongoc_stream_t *stream, const char tmp_creds_len = strlen(state->sasl.pass); /* this is donated to the sspi */ - pass = bson_array_alloc0(sizeof(WCHAR), (tmp_creds_len + 1)); + pass = BSON_ARRAY_ALLOC0((tmp_creds_len + 1), WCHAR); pass_len = MultiByteToWideChar(CP_UTF8, 0, state->sasl.pass, (int)tmp_creds_len, pass, (int)tmp_creds_len); pass[pass_len] = L'\0'; } @@ -84,7 +84,7 @@ _mongoc_cluster_sspi_new(mongoc_uri_t *uri, mongoc_stream_t *stream, const char tmp_creds_len = strlen(state->sasl.user); /* this is donated to the sspi */ - user = bson_array_alloc0(sizeof(WCHAR), (tmp_creds_len + 1)); + user = BSON_ARRAY_ALLOC0((tmp_creds_len + 1), WCHAR); user_len = MultiByteToWideChar(CP_UTF8, 0, state->sasl.user, (int)tmp_creds_len, user, (int)tmp_creds_len); user[user_len] = L'\0'; } @@ -222,7 +222,7 @@ _mongoc_cluster_auth_node_sspi(mongoc_cluster_t *cluster, tmpstr = bson_iter_utf8(&iter, &buflen); bson_free(buf); - buf = bson_array_alloc(sizeof(SEC_CHAR), (buflen + 1)); + buf = BSON_ARRAY_ALLOC((buflen + 1), SEC_CHAR); memcpy(buf, tmpstr, buflen); buf[buflen] = (SEC_CHAR)0; diff --git a/src/libmongoc/src/mongoc/mongoc-scram.c b/src/libmongoc/src/mongoc/mongoc-scram.c index 84fe439fff..642aa86f35 100644 --- a/src/libmongoc/src/mongoc/mongoc-scram.c +++ b/src/libmongoc/src/mongoc/mongoc-scram.c @@ -1026,7 +1026,7 @@ _mongoc_sasl_prep_impl(const char *name, const char *in_utf8, bson_error_t *err) /* convert to unicode. */ BSON_ASSERT(mlib_cmp(num_chars, <=, SIZE_MAX / sizeof(uint32_t) - 1)); - utf8_codepoints = bson_array_alloc(sizeof(uint32_t), ((size_t)num_chars + 1u)); /* add one for trailing 0 value. */ + utf8_codepoints = BSON_ARRAY_ALLOC(((size_t)num_chars + 1u), uint32_t); /* add one for trailing 0 value. */ const char *c = in_utf8; mlib_foreach_irange (i, num_chars) { @@ -1083,7 +1083,7 @@ _mongoc_sasl_prep_impl(const char *name, const char *in_utf8, bson_error_t *err) utf8_pre_norm_len += len; } } - char *utf8_pre_norm = (char *)bson_array_alloc(sizeof(char), (utf8_pre_norm_len + 1)); + char *utf8_pre_norm = BSON_ARRAY_ALLOC((utf8_pre_norm_len + 1), char); char *loc = utf8_pre_norm; mlib_foreach_irange (i, num_chars) { diff --git a/src/libmongoc/src/mongoc/mongoc-secure-channel.c b/src/libmongoc/src/mongoc/mongoc-secure-channel.c index 97c87bb3d2..ed46b370e7 100644 --- a/src/libmongoc/src/mongoc/mongoc-secure-channel.c +++ b/src/libmongoc/src/mongoc/mongoc-secure-channel.c @@ -233,7 +233,7 @@ utf8_to_wide(const char *utf8) } // Since -1 was passed as the input length, the returned character count includes space for the null character. - WCHAR *wide_chars = bson_array_alloc(sizeof(WCHAR), required_wide_chars); + WCHAR *wide_chars = BSON_ARRAY_ALLOC(required_wide_chars, WCHAR); if (0 == MultiByteToWideChar(CP_UTF8, 0, utf8, -1 /* NULL terminated */, wide_chars, required_wide_chars)) { bson_free(wide_chars); return NULL; diff --git a/src/libmongoc/src/mongoc/mongoc-server-description.c b/src/libmongoc/src/mongoc/mongoc-server-description.c index ca56ceb5f9..8748ce6ac5 100644 --- a/src/libmongoc/src/mongoc/mongoc-server-description.c +++ b/src/libmongoc/src/mongoc/mongoc-server-description.c @@ -987,7 +987,7 @@ mongoc_server_description_filter_tags(const mongoc_server_description_t **descri return; } - sd_matched = (bool *)bson_array_alloc0(sizeof(bool), description_len); + sd_matched = BSON_ARRAY_ALLOC0(description_len, bool); bson_iter_init(&rp_tagset_iter, rp_tags); diff --git a/src/libmongoc/src/mongoc/mongoc-set.c b/src/libmongoc/src/mongoc/mongoc-set.c index dec8e162ab..b0b4fbe0e8 100644 --- a/src/libmongoc/src/mongoc/mongoc-set.c +++ b/src/libmongoc/src/mongoc/mongoc-set.c @@ -27,7 +27,7 @@ mongoc_set_new(size_t nitems, mongoc_set_item_dtor dtor, void *dtor_ctx) mongoc_set_t *set = (mongoc_set_t *)bson_malloc(sizeof(*set)); set->items_allocated = BSON_MAX(nitems, 1); - set->items = (mongoc_set_item_t *)bson_array_alloc(sizeof(*set->items), set->items_allocated); + set->items = BSON_ARRAY_ALLOC(set->items_allocated, mongoc_set_item_t); set->items_len = 0; set->dtor = dtor; @@ -208,7 +208,7 @@ mongoc_set_for_each_with_id(mongoc_set_t *set, mongoc_set_for_each_with_id_cb_t return; } - mongoc_set_item_t *const old_set = bson_array_alloc(sizeof(*old_set), items_len); + mongoc_set_item_t *const old_set = BSON_ARRAY_ALLOC(items_len, mongoc_set_item_t); memcpy(old_set, set->items, sizeof(*old_set) * items_len); for (uint32_t i = 0u; i < items_len; i++) { @@ -237,7 +237,7 @@ mongoc_set_for_each_with_id_const(const mongoc_set_t *set, mongoc_set_for_each_w return; } - mongoc_set_item_t *const old_set = bson_array_alloc(sizeof(*old_set), items_len); + mongoc_set_item_t *const old_set = BSON_ARRAY_ALLOC(items_len, mongoc_set_item_t); memcpy(old_set, set->items, sizeof(*old_set) * items_len); for (uint32_t i = 0u; i < items_len; i++) { diff --git a/src/libmongoc/src/mongoc/mongoc-socket.c b/src/libmongoc/src/mongoc/mongoc-socket.c index 91af25d1b9..9231df1a12 100644 --- a/src/libmongoc/src/mongoc/mongoc-socket.c +++ b/src/libmongoc/src/mongoc/mongoc-socket.c @@ -336,7 +336,7 @@ mongoc_socket_poll(mongoc_socket_poll_t *sds, /* IN */ } } #else - pfds = (struct pollfd *)bson_array_alloc(sizeof(*pfds), nsds); + pfds = BSON_ARRAY_ALLOC(nsds, struct pollfd); for (size_t i = 0u; i < nsds; i++) { pfds[i].fd = sds[i].socket->sd; @@ -1349,7 +1349,7 @@ mongoc_socket_sendv(mongoc_socket_t *sock, /* IN */ BSON_ASSERT(in_iov); BSON_ASSERT(iovcnt); - iov = bson_array_alloc(sizeof(*iov), iovcnt); + iov = BSON_ARRAY_ALLOC(iovcnt, mongoc_iovec_t); memcpy(iov, in_iov, sizeof(*iov) * iovcnt); for (;;) { diff --git a/src/libmongoc/src/mongoc/mongoc-sspi.c b/src/libmongoc/src/mongoc/mongoc-sspi.c index 43b8d3f797..3d57837d70 100644 --- a/src/libmongoc/src/mongoc/mongoc-sspi.c +++ b/src/libmongoc/src/mongoc/mongoc-sspi.c @@ -69,7 +69,7 @@ _mongoc_sspi_base64_encode(const SEC_CHAR *value, DWORD vlen) DWORD len; /* Get the correct size for the out buffer. */ if (CryptBinaryToStringA((BYTE *)value, vlen, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, NULL, &len)) { - out = (SEC_CHAR *)bson_array_alloc(sizeof(SEC_CHAR), len); + out = BSON_ARRAY_ALLOC(len, SEC_CHAR); if (out) { /* Encode to the out buffer. */ if (CryptBinaryToStringA((BYTE *)value, vlen, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, out, &len)) { @@ -89,7 +89,7 @@ _mongoc_sspi_base64_decode(const SEC_CHAR *value, DWORD *rlen) SEC_CHAR *out = NULL; /* Get the correct size for the out buffer. */ if (CryptStringToBinaryA(value, 0, CRYPT_STRING_BASE64, NULL, rlen, NULL, NULL)) { - out = (SEC_CHAR *)bson_array_alloc(sizeof(SEC_CHAR), *rlen); + out = BSON_ARRAY_ALLOC(*rlen, SEC_CHAR); if (out) { /* Decode to the out buffer. */ if (CryptStringToBinaryA(value, 0, CRYPT_STRING_BASE64, (BYTE *)out, rlen, NULL, NULL)) { @@ -109,7 +109,7 @@ _mongoc_sspi_wide_to_utf8(WCHAR *value) CHAR *out; int len = WideCharToMultiByte(CP_UTF8, 0, value, -1, NULL, 0, NULL, NULL); if (len) { - out = (CHAR *)bson_array_alloc(sizeof(CHAR), len); + out = BSON_ARRAY_ALLOC(len, CHAR); if (WideCharToMultiByte(CP_UTF8, 0, value, -1, out, len, NULL, NULL)) { return out; } else { @@ -438,7 +438,7 @@ _mongoc_sspi_auth_sspi_client_wrap( } outbufSize = wrapBufs[0].cbBuffer + wrapBufs[1].cbBuffer + wrapBufs[2].cbBuffer; - outbuf = (SEC_CHAR *)bson_array_alloc(sizeof(SEC_CHAR), outbufSize); + outbuf = BSON_ARRAY_ALLOC(outbufSize, SEC_CHAR); memcpy_s(outbuf, outbufSize, wrapBufs[0].pvBuffer, wrapBufs[0].cbBuffer); memcpy_s( outbuf + wrapBufs[0].cbBuffer, outbufSize - wrapBufs[0].cbBuffer, wrapBufs[1].pvBuffer, wrapBufs[1].cbBuffer); diff --git a/src/libmongoc/src/mongoc/mongoc-stream-socket.c b/src/libmongoc/src/mongoc/mongoc-stream-socket.c index 28d228637b..2c020f4517 100644 --- a/src/libmongoc/src/mongoc/mongoc-stream-socket.c +++ b/src/libmongoc/src/mongoc/mongoc-stream-socket.c @@ -214,7 +214,7 @@ _mongoc_stream_socket_poll(mongoc_stream_poll_t *streams, size_t nstreams, int32 ENTRY; - sds = (mongoc_socket_poll_t *)bson_array_alloc(sizeof(*sds), nstreams); + sds = BSON_ARRAY_ALLOC(nstreams, mongoc_socket_poll_t); for (size_t i = 0u; i < nstreams; i++) { ss = (mongoc_stream_socket_t *)streams[i].stream; diff --git a/src/libmongoc/src/mongoc/mongoc-stream.c b/src/libmongoc/src/mongoc/mongoc-stream.c index cf24a683d4..515de537bb 100644 --- a/src/libmongoc/src/mongoc/mongoc-stream.c +++ b/src/libmongoc/src/mongoc/mongoc-stream.c @@ -335,7 +335,7 @@ mongoc_stream_poll(mongoc_stream_poll_t *streams, size_t nstreams, int32_t timeo ssize_t _mongoc_stream_poll_internal(mongoc_stream_poll_t *streams, size_t nstreams, mlib_timer until) { - mongoc_stream_poll_t *poller = (mongoc_stream_poll_t *)bson_array_alloc(sizeof(*poller), nstreams); + mongoc_stream_poll_t *poller = BSON_ARRAY_ALLOC(nstreams, mongoc_stream_poll_t); int last_type = 0; ssize_t rval = -1; diff --git a/src/libmongoc/src/mongoc/mongoc-topology-background-monitoring.c b/src/libmongoc/src/mongoc/mongoc-topology-background-monitoring.c index 2eb75d19f3..0131651fc0 100644 --- a/src/libmongoc/src/mongoc/mongoc-topology-background-monitoring.c +++ b/src/libmongoc/src/mongoc/mongoc-topology-background-monitoring.c @@ -183,7 +183,7 @@ _remove_orphaned_server_monitors(mongoc_set_t *server_monitors, mongoc_set_t *se /* Signal shutdown to server monitors no longer in the topology description. */ - server_monitor_ids_to_remove = bson_array_alloc0(sizeof(uint32_t), server_monitors->items_len); + server_monitor_ids_to_remove = BSON_ARRAY_ALLOC0(server_monitors->items_len, uint32_t); for (size_t i = 0u; i < server_monitors->items_len; i++) { mongoc_server_monitor_t *server_monitor; uint32_t id; diff --git a/src/libmongoc/src/mongoc/mongoc-topology-description.c b/src/libmongoc/src/mongoc/mongoc-topology-description.c index 896391942f..8d40ac1243 100644 --- a/src/libmongoc/src/mongoc/mongoc-topology-description.c +++ b/src/libmongoc/src/mongoc/mongoc-topology-description.c @@ -798,7 +798,7 @@ mongoc_topology_description_suitable_servers(mongoc_array_t *set, /* OUT */ .topology_type = topology->type, .has_secondary = false, .candidates_len = 0, - .candidates = bson_array_alloc0(sizeof(mongoc_server_description_t *), td_servers->items_len), + .candidates = BSON_ARRAY_ALLOC0(td_servers->items_len, const mongoc_server_description_t *), }; /* The "effective" read mode is the read mode that we should behave for, and @@ -2370,7 +2370,7 @@ mongoc_topology_description_get_servers(const mongoc_topology_description_t *td, { const mongoc_set_t *const set = mc_tpld_servers_const(BSON_ASSERT_PTR_INLINE(td)); /* enough room for all descriptions, even if some are unknown */ - mongoc_server_description_t **sds = bson_array_alloc0(sizeof(mongoc_server_description_t *), set->items_len); + mongoc_server_description_t **sds = BSON_ARRAY_ALLOC0(set->items_len, mongoc_server_description_t *); BSON_ASSERT_PARAM(n); diff --git a/src/libmongoc/src/mongoc/mongoc-topology.c b/src/libmongoc/src/mongoc/mongoc-topology.c index 0656f8dab2..ce634fe33b 100644 --- a/src/libmongoc/src/mongoc/mongoc-topology.c +++ b/src/libmongoc/src/mongoc/mongoc-topology.c @@ -268,7 +268,7 @@ _mongoc_apply_srv_max_hosts(const mongoc_host_list_t *hl, size_t max_hosts, size return NULL; } - hl_array = bson_array_alloc(sizeof(mongoc_host_list_t *), hl_size); + hl_array = BSON_ARRAY_ALLOC(hl_size, const mongoc_host_list_t *); for (size_t idx = 0u; hl; hl = hl->next) { hl_array[idx++] = hl; From 27caedeae206d3c9c8cef483449bb81ffc9fc466 Mon Sep 17 00:00:00 2001 From: Julia-Garland Date: Wed, 3 Sep 2025 15:22:31 -0400 Subject: [PATCH 10/13] Remove "at least sizeof(void*) bytes" from documentation --- src/libbson/doc/bson_aligned_alloc.rst | 2 -- src/libbson/doc/bson_aligned_alloc0.rst | 2 -- src/libbson/doc/bson_array_alloc.rst | 2 -- src/libbson/doc/bson_array_alloc0.rst | 2 -- src/libbson/doc/bson_malloc.rst | 2 -- src/libbson/doc/bson_malloc0.rst | 2 -- src/libbson/doc/bson_realloc.rst | 2 +- 7 files changed, 1 insertion(+), 13 deletions(-) diff --git a/src/libbson/doc/bson_aligned_alloc.rst b/src/libbson/doc/bson_aligned_alloc.rst index 0007f43fcb..7e7d859a93 100644 --- a/src/libbson/doc/bson_aligned_alloc.rst +++ b/src/libbson/doc/bson_aligned_alloc.rst @@ -22,8 +22,6 @@ Description This is a portable ``aligned_alloc()`` wrapper. -In general, this function will return an allocation at least ``sizeof(void*)`` bytes or bigger with an alignment of at least ``alignment``. - If there was a failure to allocate ``num_bytes`` bytes aligned to ``alignment``, the process will be aborted. .. warning:: diff --git a/src/libbson/doc/bson_aligned_alloc0.rst b/src/libbson/doc/bson_aligned_alloc0.rst index 2608b580cc..4b8e2c1f88 100644 --- a/src/libbson/doc/bson_aligned_alloc0.rst +++ b/src/libbson/doc/bson_aligned_alloc0.rst @@ -22,8 +22,6 @@ Description This is a portable ``aligned_alloc()`` wrapper that also sets the memory to zero. -In general, this function will return an allocation at least ``sizeof(void*)`` bytes or bigger with an alignment of at least ``alignment``. - If there was a failure to allocate ``num_bytes`` bytes aligned to ``alignment``, the process will be aborted. .. warning:: diff --git a/src/libbson/doc/bson_array_alloc.rst b/src/libbson/doc/bson_array_alloc.rst index f3f17db9fb..c5a559b9bf 100644 --- a/src/libbson/doc/bson_array_alloc.rst +++ b/src/libbson/doc/bson_array_alloc.rst @@ -25,8 +25,6 @@ Description This is a portable ``malloc()`` wrapper to allocate an array of objects. -In general, this function will return an allocation at least ``sizeof(void*)`` bytes or bigger. - If there was a failure to allocate ``num_elems * elem_size`` bytes, the process will be aborted. .. warning:: diff --git a/src/libbson/doc/bson_array_alloc0.rst b/src/libbson/doc/bson_array_alloc0.rst index 91f5f22b52..a6a718ca17 100644 --- a/src/libbson/doc/bson_array_alloc0.rst +++ b/src/libbson/doc/bson_array_alloc0.rst @@ -25,8 +25,6 @@ Description This is a portable ``calloc()`` wrapper to allocate an array of objects that also sets the memory to zero. -In general, this function will return an allocation at least ``sizeof(void*)`` bytes or bigger. - If there was a failure to allocate ``num_elems * elem_size`` bytes, the process will be aborted. .. warning:: diff --git a/src/libbson/doc/bson_malloc.rst b/src/libbson/doc/bson_malloc.rst index f7a09c4cb8..0bc955f367 100644 --- a/src/libbson/doc/bson_malloc.rst +++ b/src/libbson/doc/bson_malloc.rst @@ -21,8 +21,6 @@ Description This is a portable ``malloc()`` wrapper. -In general, this function will return an allocation at least ``sizeof(void*)`` bytes or bigger. - If there was a failure to allocate ``num_bytes`` bytes, the process will be aborted. .. warning:: diff --git a/src/libbson/doc/bson_malloc0.rst b/src/libbson/doc/bson_malloc0.rst index bbab2fb089..33da6f7887 100644 --- a/src/libbson/doc/bson_malloc0.rst +++ b/src/libbson/doc/bson_malloc0.rst @@ -21,8 +21,6 @@ Description This is a portable ``malloc()`` wrapper that also sets the memory to zero. Similar to ``calloc()``. -In general, this function will return an allocation at least ``sizeof(void*)`` bytes or bigger. - If there was a failure to allocate ``num_bytes`` bytes, the process will be aborted. .. warning:: diff --git a/src/libbson/doc/bson_realloc.rst b/src/libbson/doc/bson_realloc.rst index ad9e802720..c94da20c27 100644 --- a/src/libbson/doc/bson_realloc.rst +++ b/src/libbson/doc/bson_realloc.rst @@ -22,7 +22,7 @@ Description This is a portable ``realloc()`` wrapper. -In general, this function will return an allocation at least ``sizeof(void*)`` bytes or bigger. If ``num_bytes`` is 0, then the allocation will be freed. +If ``num_bytes`` is 0, then the allocation will be freed. If there was a failure to allocate ``num_bytes`` bytes, the process will be aborted. From 286c43a356c52375ad45e085ec5cacaf50f5f85c Mon Sep 17 00:00:00 2001 From: Julia-Garland Date: Wed, 3 Sep 2025 15:50:49 -0400 Subject: [PATCH 11/13] kevinAlbs suggestions --- src/libbson/doc/bson_array_alloc.rst | 2 +- src/libbson/doc/bson_array_alloc0.rst | 2 +- src/libbson/src/bson/memory.c | 17 +++++++++-------- src/libbson/tests/test-bson.c | 20 ++++++++++++++++++++ 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/libbson/doc/bson_array_alloc.rst b/src/libbson/doc/bson_array_alloc.rst index c5a559b9bf..d2c9aab827 100644 --- a/src/libbson/doc/bson_array_alloc.rst +++ b/src/libbson/doc/bson_array_alloc.rst @@ -25,7 +25,7 @@ Description This is a portable ``malloc()`` wrapper to allocate an array of objects. -If there was a failure to allocate ``num_elems * elem_size`` bytes, the process will be aborted. +If ``num_elems * elem_size`` cannot be represented in a size_t or there was a failure to allocate ``num_elems * elem_size`` bytes, the process will be aborted. .. warning:: diff --git a/src/libbson/doc/bson_array_alloc0.rst b/src/libbson/doc/bson_array_alloc0.rst index a6a718ca17..c0ade26be7 100644 --- a/src/libbson/doc/bson_array_alloc0.rst +++ b/src/libbson/doc/bson_array_alloc0.rst @@ -25,7 +25,7 @@ Description This is a portable ``calloc()`` wrapper to allocate an array of objects that also sets the memory to zero. -If there was a failure to allocate ``num_elems * elem_size`` bytes, the process will be aborted. +If ``num_elems * elem_size`` cannot be represented in a size_t or there was a failure to allocate ``num_elems * elem_size`` bytes, the process will be aborted. .. warning:: diff --git a/src/libbson/src/bson/memory.c b/src/libbson/src/bson/memory.c index b3240f8fae..4e73017c9b 100644 --- a/src/libbson/src/bson/memory.c +++ b/src/libbson/src/bson/memory.c @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -247,8 +248,7 @@ bson_aligned_alloc0(size_t alignment /* IN */, size_t num_bytes /* IN */) * * Returns: * A pointer if successful; otherwise abort() is called and this - * function will never return. In the cases of num_elems = 0 or - * integer overflow in num_elems * elem_size, NULL is returned. + * function will never return. * *-------------------------------------------------------------------------- */ @@ -257,9 +257,10 @@ void * bson_array_alloc(size_t num_elems /* IN */, size_t elem_size /* IN */) { void *mem = NULL; - size_t num_bytes = num_elems * elem_size; + size_t num_bytes; + BSON_ASSERT(!mlib_mul(&num_bytes, num_elems, elem_size)); - if (BSON_LIKELY(num_bytes) && BSON_LIKELY(num_elems == num_bytes / elem_size)) { + if (BSON_LIKELY(num_bytes)) { mem = bson_malloc(num_bytes); } return mem; @@ -279,8 +280,7 @@ bson_array_alloc(size_t num_elems /* IN */, size_t elem_size /* IN */) * * Returns: * A pointer if successful; otherwise abort() is called and this - * function will never return. In the cases of num_elems = 0 or - * integer overflow in num_elems * elem_size, NULL is returned. + * function will never return. * * Side effects: * None. @@ -292,9 +292,10 @@ void * bson_array_alloc0(size_t num_elems /* IN */, size_t elem_size /* IN */) { void *mem = NULL; - size_t num_bytes = num_elems * elem_size; + size_t num_bytes; + BSON_ASSERT(!mlib_mul(&num_bytes, num_elems, elem_size)); - if (BSON_LIKELY(num_bytes) && BSON_LIKELY(num_elems == num_bytes / elem_size)) { + if (BSON_LIKELY(num_bytes)) { if (BSON_UNLIKELY(!(mem = gMemVtable.calloc(num_elems, elem_size)))) { fprintf(stderr, "Failure to allocate memory in bson_array_alloc0(). errno: %d.\n", errno); abort(); diff --git a/src/libbson/tests/test-bson.c b/src/libbson/tests/test-bson.c index 5cd40e15cf..80ebffe6a6 100644 --- a/src/libbson/tests/test-bson.c +++ b/src/libbson/tests/test-bson.c @@ -124,6 +124,25 @@ test_bson_alloc(void) } +static void +test_bson_array_alloc(void) +{ + // Can allocate an array of items: + { + int *arr = BSON_ARRAY_ALLOC(2, int); + arr[0] = 1; + arr[1] = 2; + bson_free(arr); + } + + // Allocating with overflow in byte size aborts: + mlib_assert_aborts () { + int *arr = BSON_ARRAY_ALLOC(SIZE_MAX, int); + bson_free(arr); + } +} + + static void BSON_ASSERT_BSON_EQUAL(const bson_t *a, const bson_t *b) { @@ -2971,6 +2990,7 @@ test_bson_install(TestSuite *suite) TestSuite_Add(suite, "/bson/init", test_bson_init); TestSuite_Add(suite, "/bson/init_static", test_bson_init_static); TestSuite_Add(suite, "/bson/basic", test_bson_alloc); + TestSuite_Add(suite, "/bson/basic_array_alloc", test_bson_array_alloc); TestSuite_Add(suite, "/bson/append_overflow", test_bson_append_overflow); TestSuite_Add(suite, "/bson/append_array", test_bson_append_array); TestSuite_Add(suite, "/bson/append_binary", test_bson_append_binary); From 03910dbe9d04670ff79d9aef57e7dab14170a825 Mon Sep 17 00:00:00 2001 From: Julia-Garland Date: Wed, 3 Sep 2025 16:05:59 -0400 Subject: [PATCH 12/13] Tweak mlib include --- src/libbson/src/bson/memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libbson/src/bson/memory.c b/src/libbson/src/bson/memory.c index 4e73017c9b..8ce0d7e9f4 100644 --- a/src/libbson/src/bson/memory.c +++ b/src/libbson/src/bson/memory.c @@ -21,8 +21,8 @@ #include +#include #include -#include #include #include From 520ee4d29d23267620b52c4e971310717752c6c5 Mon Sep 17 00:00:00 2001 From: Julia-Garland Date: Wed, 3 Sep 2025 16:08:57 -0400 Subject: [PATCH 13/13] Initialize num_bytes --- src/libbson/src/bson/memory.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libbson/src/bson/memory.c b/src/libbson/src/bson/memory.c index 8ce0d7e9f4..0d84ea53e5 100644 --- a/src/libbson/src/bson/memory.c +++ b/src/libbson/src/bson/memory.c @@ -257,7 +257,7 @@ void * bson_array_alloc(size_t num_elems /* IN */, size_t elem_size /* IN */) { void *mem = NULL; - size_t num_bytes; + size_t num_bytes = 0; BSON_ASSERT(!mlib_mul(&num_bytes, num_elems, elem_size)); if (BSON_LIKELY(num_bytes)) { @@ -292,7 +292,7 @@ void * bson_array_alloc0(size_t num_elems /* IN */, size_t elem_size /* IN */) { void *mem = NULL; - size_t num_bytes; + size_t num_bytes = 0; BSON_ASSERT(!mlib_mul(&num_bytes, num_elems, elem_size)); if (BSON_LIKELY(num_bytes)) {