|
31 | 31 | #include <string.h>
|
32 | 32 | #endif
|
33 | 33 |
|
| 34 | +// `bson_next_power_of_two_u32` returns 0 on overflow. |
| 35 | +static BSON_INLINE uint32_t |
| 36 | +bson_next_power_of_two_u32 (uint32_t v) |
| 37 | +{ |
| 38 | + BSON_ASSERT (v > 0); |
| 39 | + |
| 40 | + // https://graphics.stanford.edu/%7Eseander/bithacks.html#RoundUpPowerOf2 |
| 41 | + v--; |
| 42 | + v |= v >> 1; |
| 43 | + v |= v >> 2; |
| 44 | + v |= v >> 4; |
| 45 | + v |= v >> 8; |
| 46 | + v |= v >> 16; |
| 47 | + v++; |
| 48 | + |
| 49 | + return v; |
| 50 | +} |
| 51 | + |
| 52 | +// `bson_string_ensure_space` ensures `string` has enough room for `needed` + a null terminator. |
| 53 | +static void |
| 54 | +bson_string_ensure_space (bson_string_t *string, uint32_t needed) |
| 55 | +{ |
| 56 | + BSON_ASSERT_PARAM (string); |
| 57 | + BSON_ASSERT (needed <= UINT32_MAX - 1u); |
| 58 | + needed += 1u; // Add one for trailing NULL byte. |
| 59 | + if (string->alloc >= needed) { |
| 60 | + return; |
| 61 | + } |
| 62 | + // Get the next largest power of 2 if possible. |
| 63 | + uint32_t alloc = bson_next_power_of_two_u32 (needed); |
| 64 | + if (alloc == 0) { |
| 65 | + // Overflowed: saturate at UINT32_MAX. |
| 66 | + alloc = UINT32_MAX; |
| 67 | + } |
| 68 | + if (!string->str) { |
| 69 | + string->str = bson_malloc (alloc); |
| 70 | + } else { |
| 71 | + string->str = bson_realloc (string->str, alloc); |
| 72 | + } |
| 73 | + string->alloc = alloc; |
| 74 | +} |
| 75 | + |
34 | 76 | /*
|
35 | 77 | *--------------------------------------------------------------------------
|
36 | 78 | *
|
@@ -62,33 +104,18 @@ bson_string_t *
|
62 | 104 | bson_string_new (const char *str) /* IN */
|
63 | 105 | {
|
64 | 106 | bson_string_t *ret;
|
65 |
| - size_t len_sz; |
66 | 107 |
|
67 | 108 | ret = bson_malloc0 (sizeof *ret);
|
| 109 | + const size_t len_sz = str == NULL ? 0u : strlen (str); |
| 110 | + BSON_ASSERT (bson_in_range_unsigned (uint32_t, len_sz)); |
| 111 | + const uint32_t len_u32 = (uint32_t) len_sz; |
| 112 | + bson_string_ensure_space (ret, len_u32); |
68 | 113 | if (str) {
|
69 |
| - len_sz = strlen (str); |
70 |
| - BSON_ASSERT (len_sz <= UINT32_MAX); |
71 |
| - ret->len = (uint32_t) len_sz; |
72 |
| - } else { |
73 |
| - ret->len = 0; |
74 |
| - } |
75 |
| - ret->alloc = ret->len + 1; |
76 |
| - |
77 |
| - if (!bson_is_power_of_two (ret->alloc)) { |
78 |
| - len_sz = bson_next_power_of_two ((size_t) ret->alloc); |
79 |
| - BSON_ASSERT (len_sz <= UINT32_MAX); |
80 |
| - ret->alloc = (uint32_t) len_sz; |
81 |
| - } |
82 |
| - |
83 |
| - BSON_ASSERT (ret->alloc >= ret->len + 1); |
84 |
| - |
85 |
| - ret->str = bson_malloc (ret->alloc); |
86 |
| - |
87 |
| - if (str) { |
88 |
| - memcpy (ret->str, str, ret->len); |
| 114 | + memcpy (ret->str, str, len_sz); |
89 | 115 | }
|
90 | 116 |
|
91 |
| - ret->str[ret->len] = '\0'; |
| 117 | + ret->str[len_u32] = '\0'; |
| 118 | + ret->len = len_u32; |
92 | 119 |
|
93 | 120 | return ret;
|
94 | 121 | }
|
@@ -135,31 +162,18 @@ void
|
135 | 162 | bson_string_append (bson_string_t *string, /* IN */
|
136 | 163 | const char *str) /* IN */
|
137 | 164 | {
|
138 |
| - uint32_t len; |
139 |
| - size_t len_sz; |
140 |
| - |
141 | 165 | BSON_ASSERT (string);
|
142 | 166 | BSON_ASSERT (str);
|
143 | 167 |
|
144 |
| - len_sz = strlen (str); |
| 168 | + const size_t len_sz = strlen (str); |
145 | 169 | BSON_ASSERT (bson_in_range_unsigned (uint32_t, len_sz));
|
146 |
| - len = (uint32_t) len_sz; |
147 |
| - |
148 |
| - if ((string->alloc - string->len - 1) < len) { |
149 |
| - BSON_ASSERT (string->alloc <= UINT32_MAX - len); |
150 |
| - string->alloc += len; |
151 |
| - if (!bson_is_power_of_two (string->alloc)) { |
152 |
| - len_sz = bson_next_power_of_two ((size_t) string->alloc); |
153 |
| - BSON_ASSERT (len_sz <= UINT32_MAX); |
154 |
| - string->alloc = (uint32_t) len_sz; |
155 |
| - } |
156 |
| - BSON_ASSERT (string->alloc >= string->len + len); |
157 |
| - string->str = bson_realloc (string->str, string->alloc); |
158 |
| - } |
159 |
| - |
160 |
| - memcpy (string->str + string->len, str, len); |
161 |
| - string->len += len; |
162 |
| - string->str[string->len] = '\0'; |
| 170 | + const uint32_t len_u32 = (uint32_t) len_sz; |
| 171 | + BSON_ASSERT (len_u32 <= UINT32_MAX - string->len); |
| 172 | + const uint32_t new_len = len_u32 + string->len; |
| 173 | + bson_string_ensure_space (string, new_len); |
| 174 | + memcpy (string->str + string->len, str, len_sz); |
| 175 | + string->str[new_len] = '\0'; |
| 176 | + string->len = new_len; |
163 | 177 | }
|
164 | 178 |
|
165 | 179 |
|
|
0 commit comments