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.
@@ -2018,7 +2057,7 @@ bson_copy_to (const bson_t *src, bson_t *dst)
2018
2057
}
2019
2058
2020
2059
data = _bson_data (src );
2021
- len = bson_next_power_of_two ((size_t ) src -> len );
2060
+ len = _bson_next_power_of_two_for_alloc ((size_t ) src -> len );
2022
2061
2023
2062
adst = (bson_impl_alloc_t * ) dst ;
2024
2063
adst -> flags = BSON_FLAG_STATIC ;
@@ -2140,15 +2179,24 @@ bson_reserve_buffer (bson_t *bson, uint32_t size)
2140
2179
return NULL ;
2141
2180
}
2142
2181
2143
- if (!_bson_grow (bson , size )) {
2182
+ /* The caller wants a total document size of "size".
2183
+ * Note that the bson_t can also include space for parent or sibling documents (offset) and for trailing bytes
2184
+ * (depth). These sizes will be considered by _bson_grow() but we can assume they are zero in documents without
2185
+ * 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
2186
+ * correct to ignore offset: we set the size of the current document, leaving previous documents alone. */
2187
+ if (size > bson -> len && !_bson_grow (bson , size - bson -> len )) {
2188
+ // Will fail due to overflow or when reallocation is needed on a buffer that does not support it.
2144
2189
return NULL ;
2145
2190
}
2146
2191
2147
2192
if (bson -> flags & BSON_FLAG_INLINE ) {
2148
2193
/* bson_grow didn't spill over */
2149
2194
((bson_impl_inline_t * ) bson )-> len = size ;
2195
+ BSON_ASSERT (size <= BSON_INLINE_DATA_SIZE );
2150
2196
} else {
2151
- ((bson_impl_alloc_t * ) bson )-> len = size ;
2197
+ bson_impl_alloc_t * impl = (bson_impl_alloc_t * ) bson ;
2198
+ impl -> len = size ;
2199
+ BSON_ASSERT (impl -> offset <= * impl -> buflen && * impl -> buflen - impl -> offset >= (size_t ) size );
2152
2200
}
2153
2201
2154
2202
return _bson_data (bson );
0 commit comments