21
21
#include <bson/bson-json-private.h>
22
22
#include <common-string-private.h>
23
23
#include <common-json-private.h>
24
+ #include <common-macros-private.h>
24
25
#include <bson/bson-iso8601-private.h>
25
26
26
27
#include <string.h>
@@ -60,6 +61,36 @@ typedef struct {
60
61
*/
61
62
static const uint8_t gZero ;
62
63
64
+ /*
65
+ *--------------------------------------------------------------------------
66
+ *
67
+ * _bson_next_power_of_two_for_alloc --
68
+ *
69
+ * Given a potential allocation length in bytes, round up to the
70
+ * next power of two without exceeding BSON_MAX_SIZE.
71
+ *
72
+ * Returns:
73
+ * If the input is <= BSON_MAX_SIZE, returns a value >= the input
74
+ * and still <= BSON_MAX_SIZE. If the input was greater than
75
+ * BSON_MAX_SIZE, it is returned unmodified.
76
+ *
77
+ * Side effects:
78
+ * None.
79
+ *
80
+ *--------------------------------------------------------------------------
81
+ */
82
+
83
+ static BSON_INLINE size_t
84
+ _bson_next_power_of_two_for_alloc (size_t size )
85
+ {
86
+ if (size <= BSON_MAX_SIZE ) {
87
+ size_t power_of_two = bson_next_power_of_two (size );
88
+ return BSON_MIN (power_of_two , BSON_MAX_SIZE );
89
+ } else {
90
+ return size ;
91
+ }
92
+ }
93
+
63
94
/*
64
95
*--------------------------------------------------------------------------
65
96
*
@@ -90,7 +121,7 @@ _bson_impl_inline_grow (bson_impl_inline_t *impl, /* IN */
90
121
return true;
91
122
}
92
123
93
- req = bson_next_power_of_two (impl -> len + size );
124
+ req = _bson_next_power_of_two_for_alloc (impl -> len + size );
94
125
95
126
if (req <= BSON_MAX_SIZE ) {
96
127
data = bson_malloc (req );
@@ -122,11 +153,12 @@ _bson_impl_inline_grow (bson_impl_inline_t *impl, /* IN */
122
153
*
123
154
* _bson_impl_alloc_grow --
124
155
*
125
- * Document growth implementation for documents containing malloc
126
- * based buffers .
156
+ * Document growth implementation for non-inline documents, possibly
157
+ * containing a reallocatable buffer .
127
158
*
128
159
* Returns:
129
- * true if successful; otherwise false indicating BSON_MAX_SIZE overflow.
160
+ * true if successful; otherwise false indicating BSON_MAX_SIZE overflow
161
+ * or an attempt to grow a buffer with no realloc implementation.
130
162
*
131
163
* Side effects:
132
164
* None.
@@ -143,14 +175,20 @@ _bson_impl_alloc_grow (bson_impl_alloc_t *impl, /* IN */
143
175
/*
144
176
* Determine how many bytes we need for this document in the buffer
145
177
* including necessary trailing bytes for parent documents.
178
+ *
179
+ * Note that the buffer offset and nesting depth are not available
180
+ * outside bson_impl_alloc_t, meaning it's not possible for callers to
181
+ * fully rule out BSON_MAX_SIZE overflow before _bson_grow().
182
+ * Some earlier checks against BSON_MAX_SIZE serve to prevent intermediate
183
+ * overflows rather than to validate the final allocation size.
146
184
*/
147
185
req = (impl -> offset + impl -> len + size + impl -> depth );
148
186
149
187
if (req <= * impl -> buflen ) {
150
188
return true;
151
189
}
152
190
153
- req = bson_next_power_of_two (req );
191
+ req = _bson_next_power_of_two_for_alloc (req );
154
192
155
193
if ((req <= BSON_MAX_SIZE ) && impl -> realloc ) {
156
194
* impl -> buf = impl -> realloc (* impl -> buf , req , impl -> realloc_func_ctx );
@@ -168,10 +206,11 @@ _bson_impl_alloc_grow (bson_impl_alloc_t *impl, /* IN */
168
206
* _bson_grow --
169
207
*
170
208
* Grows the bson_t structure to be large enough to contain @size
171
- * bytes.
209
+ * bytes in addition to its current content .
172
210
*
173
211
* Returns:
174
- * true if successful, false if the size would overflow.
212
+ * true if successful, false if the size would overflow or the buffer
213
+ * needs to grow but does not support reallocation.
175
214
*
176
215
* Side effects:
177
216
* None.
@@ -2097,7 +2136,7 @@ bson_copy_to (const bson_t *src, bson_t *dst)
2097
2136
}
2098
2137
2099
2138
data = _bson_data (src );
2100
- len = bson_next_power_of_two ((size_t ) src -> len );
2139
+ len = _bson_next_power_of_two_for_alloc ((size_t ) src -> len );
2101
2140
2102
2141
adst = (bson_impl_alloc_t * ) dst ;
2103
2142
adst -> flags = BSON_FLAG_STATIC ;
@@ -2219,15 +2258,24 @@ bson_reserve_buffer (bson_t *bson, uint32_t size)
2219
2258
return NULL ;
2220
2259
}
2221
2260
2222
- if (!_bson_grow (bson , size )) {
2261
+ /* The caller wants a total document size of "size".
2262
+ * Note that the bson_t can also include space for parent or sibling documents (offset) and for trailing bytes
2263
+ * (depth). These sizes will be considered by _bson_grow() but we can assume they are zero in documents without
2264
+ * BSON_FLAG_CHILD or BSON_FLAG_IN_CHILD. If this is called on a document that's part of a bson_writer_t, it is
2265
+ * correct to ignore offset: we set the size of the current document, leaving previous documents alone. */
2266
+ if (size > bson -> len && !_bson_grow (bson , size - bson -> len )) {
2267
+ // Will fail due to overflow or when reallocation is needed on a buffer that does not support it.
2223
2268
return NULL ;
2224
2269
}
2225
2270
2226
2271
if (bson -> flags & BSON_FLAG_INLINE ) {
2227
2272
/* bson_grow didn't spill over */
2228
2273
((bson_impl_inline_t * ) bson )-> len = size ;
2274
+ BSON_ASSERT (size <= BSON_INLINE_DATA_SIZE );
2229
2275
} else {
2230
- ((bson_impl_alloc_t * ) bson )-> len = size ;
2276
+ bson_impl_alloc_t * impl = (bson_impl_alloc_t * ) bson ;
2277
+ impl -> len = size ;
2278
+ BSON_ASSERT (impl -> offset <= * impl -> buflen && * impl -> buflen - impl -> offset >= (size_t ) size );
2231
2279
}
2232
2280
2233
2281
return _bson_data (bson );
0 commit comments