Skip to content

Commit 6f732fc

Browse files
author
Micah Scott
committed
libbson bugfix, allow allocating max size documents
The power-of-two rounding was exceeding MAX_SIZE on any allocation attempts above about MAX_SIZE/2.
1 parent aea2bef commit 6f732fc

File tree

1 file changed

+38
-4
lines changed

1 file changed

+38
-4
lines changed

src/libbson/src/bson/bson.c

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <bson/bson-json-private.h>
2222
#include <common-string-private.h>
2323
#include <common-json-private.h>
24+
#include <common-macros-private.h>
2425
#include <bson/bson-iso8601-private.h>
2526

2627
#include <string.h>
@@ -60,6 +61,31 @@ typedef struct {
6061
*/
6162
static const uint8_t gZero;
6263

64+
/*
65+
*--------------------------------------------------------------------------
66+
*
67+
* _bson_next_power_of_two_for_alloc --
68+
*
69+
* Given a potential allocation length no greater than BSON_MAX_SIZE,
70+
* round it up to the next power of two without exceeding BSON_MAX_SIZE.
71+
*
72+
* Returns:
73+
* A value >= the input size and <= BSON_MAX_SIZE.
74+
*
75+
* Side effects:
76+
* None.
77+
*
78+
*--------------------------------------------------------------------------
79+
*/
80+
81+
static BSON_INLINE size_t
82+
_bson_next_power_of_two_for_alloc (size_t size)
83+
{
84+
MONGOC_DEBUG_ASSERT (size <= BSON_MAX_SIZE);
85+
size_t power_of_two = bson_next_power_of_two (size);
86+
return BSON_MIN (power_of_two, BSON_MAX_SIZE);
87+
}
88+
6389
/*
6490
*--------------------------------------------------------------------------
6591
*
@@ -90,7 +116,7 @@ _bson_impl_inline_grow (bson_impl_inline_t *impl, /* IN */
90116
return true;
91117
}
92118

93-
req = bson_next_power_of_two (impl->len + size);
119+
req = _bson_next_power_of_two_for_alloc (impl->len + size);
94120

95121
if (req <= BSON_MAX_SIZE) {
96122
data = bson_malloc (req);
@@ -150,7 +176,7 @@ _bson_impl_alloc_grow (bson_impl_alloc_t *impl, /* IN */
150176
return true;
151177
}
152178

153-
req = bson_next_power_of_two (req);
179+
req = _bson_next_power_of_two_for_alloc (req);
154180

155181
if ((req <= BSON_MAX_SIZE) && impl->realloc) {
156182
*impl->buf = impl->realloc (*impl->buf, req, impl->realloc_func_ctx);
@@ -168,7 +194,8 @@ _bson_impl_alloc_grow (bson_impl_alloc_t *impl, /* IN */
168194
* _bson_grow --
169195
*
170196
* Grows the bson_t structure to be large enough to contain @size
171-
* bytes.
197+
* bytes in addition to its current content. The caller is responsible
198+
* for ensuring the new summed size is <= BSON_MAX_SIZE.
172199
*
173200
* Returns:
174201
* true if successful, false if the size would overflow.
@@ -183,6 +210,9 @@ static bool
183210
_bson_grow (bson_t *bson, /* IN */
184211
uint32_t size) /* IN */
185212
{
213+
// Already checked by caller in all build types
214+
MONGOC_DEBUG_ASSERT ((size_t) bson->len <= BSON_MAX_SIZE && (size_t) size <= BSON_MAX_SIZE - (size_t) bson->len);
215+
186216
if ((bson->flags & BSON_FLAG_INLINE)) {
187217
return _bson_impl_inline_grow ((bson_impl_inline_t *) bson, size);
188218
}
@@ -2097,7 +2127,7 @@ bson_copy_to (const bson_t *src, bson_t *dst)
20972127
}
20982128

20992129
data = _bson_data (src);
2100-
len = bson_next_power_of_two ((size_t) src->len);
2130+
len = _bson_next_power_of_two_for_alloc ((size_t) src->len);
21012131

21022132
adst = (bson_impl_alloc_t *) dst;
21032133
adst->flags = BSON_FLAG_STATIC;
@@ -2219,6 +2249,10 @@ bson_reserve_buffer (bson_t *bson, uint32_t size)
22192249
return NULL;
22202250
}
22212251

2252+
MONGOC_DEBUG_ASSERT ((size_t) bson->len <= BSON_MAX_SIZE);
2253+
if ((size_t) size > BSON_MAX_SIZE - (size_t) bson->len) {
2254+
return NULL;
2255+
}
22222256
if (!_bson_grow (bson, size)) {
22232257
return NULL;
22242258
}

0 commit comments

Comments
 (0)