|
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