1 /**
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0.
4 */
5
6 #include <aws/common/byte_buf.h>
7 #include <aws/common/private/byte_buf.h>
8
9 #include <stdarg.h>
10
11 #ifdef _MSC_VER
12 /* disables warning non const declared initializers for Microsoft compilers */
13 # pragma warning(disable : 4204)
14 # pragma warning(disable : 4706)
15 #endif
16
aws_byte_buf_init(struct aws_byte_buf * buf,struct aws_allocator * allocator,size_t capacity)17 int aws_byte_buf_init(struct aws_byte_buf *buf, struct aws_allocator *allocator, size_t capacity) {
18 AWS_PRECONDITION(buf);
19 AWS_PRECONDITION(allocator);
20
21 buf->buffer = (capacity == 0) ? NULL : aws_mem_acquire(allocator, capacity);
22 if (capacity != 0 && buf->buffer == NULL) {
23 AWS_ZERO_STRUCT(*buf);
24 return AWS_OP_ERR;
25 }
26
27 buf->len = 0;
28 buf->capacity = capacity;
29 buf->allocator = allocator;
30 AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
31 return AWS_OP_SUCCESS;
32 }
33
aws_byte_buf_init_copy(struct aws_byte_buf * dest,struct aws_allocator * allocator,const struct aws_byte_buf * src)34 int aws_byte_buf_init_copy(struct aws_byte_buf *dest, struct aws_allocator *allocator, const struct aws_byte_buf *src) {
35 AWS_PRECONDITION(allocator);
36 AWS_PRECONDITION(dest);
37 AWS_ERROR_PRECONDITION(aws_byte_buf_is_valid(src));
38
39 if (!src->buffer) {
40 AWS_ZERO_STRUCT(*dest);
41 dest->allocator = allocator;
42 AWS_POSTCONDITION(aws_byte_buf_is_valid(dest));
43 return AWS_OP_SUCCESS;
44 }
45
46 *dest = *src;
47 dest->allocator = allocator;
48 dest->buffer = (uint8_t *)aws_mem_acquire(allocator, src->capacity);
49 if (dest->buffer == NULL) {
50 AWS_ZERO_STRUCT(*dest);
51 return AWS_OP_ERR;
52 }
53 memcpy(dest->buffer, src->buffer, src->len);
54 AWS_POSTCONDITION(aws_byte_buf_is_valid(dest));
55 return AWS_OP_SUCCESS;
56 }
57
aws_byte_buf_is_valid(const struct aws_byte_buf * const buf)58 bool aws_byte_buf_is_valid(const struct aws_byte_buf *const buf) {
59 return buf != NULL &&
60 ((buf->capacity == 0 && buf->len == 0 && buf->buffer == NULL) ||
61 (buf->capacity > 0 && buf->len <= buf->capacity && AWS_MEM_IS_WRITABLE(buf->buffer, buf->capacity)));
62 }
63
aws_byte_cursor_is_valid(const struct aws_byte_cursor * cursor)64 bool aws_byte_cursor_is_valid(const struct aws_byte_cursor *cursor) {
65 return cursor != NULL &&
66 ((cursor->len == 0) || (cursor->len > 0 && cursor->ptr && AWS_MEM_IS_READABLE(cursor->ptr, cursor->len)));
67 }
68
aws_byte_buf_reset(struct aws_byte_buf * buf,bool zero_contents)69 void aws_byte_buf_reset(struct aws_byte_buf *buf, bool zero_contents) {
70 if (zero_contents) {
71 aws_byte_buf_secure_zero(buf);
72 }
73 buf->len = 0;
74 }
75
aws_byte_buf_clean_up(struct aws_byte_buf * buf)76 void aws_byte_buf_clean_up(struct aws_byte_buf *buf) {
77 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
78 if (buf->allocator && buf->buffer) {
79 aws_mem_release(buf->allocator, (void *)buf->buffer);
80 }
81 buf->allocator = NULL;
82 buf->buffer = NULL;
83 buf->len = 0;
84 buf->capacity = 0;
85 }
86
aws_byte_buf_secure_zero(struct aws_byte_buf * buf)87 void aws_byte_buf_secure_zero(struct aws_byte_buf *buf) {
88 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
89 if (buf->buffer) {
90 aws_secure_zero(buf->buffer, buf->capacity);
91 }
92 buf->len = 0;
93 AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
94 }
95
aws_byte_buf_clean_up_secure(struct aws_byte_buf * buf)96 void aws_byte_buf_clean_up_secure(struct aws_byte_buf *buf) {
97 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
98 aws_byte_buf_secure_zero(buf);
99 aws_byte_buf_clean_up(buf);
100 AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
101 }
102
aws_byte_buf_eq(const struct aws_byte_buf * const a,const struct aws_byte_buf * const b)103 bool aws_byte_buf_eq(const struct aws_byte_buf *const a, const struct aws_byte_buf *const b) {
104 AWS_PRECONDITION(aws_byte_buf_is_valid(a));
105 AWS_PRECONDITION(aws_byte_buf_is_valid(b));
106 bool rval = aws_array_eq(a->buffer, a->len, b->buffer, b->len);
107 AWS_POSTCONDITION(aws_byte_buf_is_valid(a));
108 AWS_POSTCONDITION(aws_byte_buf_is_valid(b));
109 return rval;
110 }
111
aws_byte_buf_eq_ignore_case(const struct aws_byte_buf * const a,const struct aws_byte_buf * const b)112 bool aws_byte_buf_eq_ignore_case(const struct aws_byte_buf *const a, const struct aws_byte_buf *const b) {
113 AWS_PRECONDITION(aws_byte_buf_is_valid(a));
114 AWS_PRECONDITION(aws_byte_buf_is_valid(b));
115 bool rval = aws_array_eq_ignore_case(a->buffer, a->len, b->buffer, b->len);
116 AWS_POSTCONDITION(aws_byte_buf_is_valid(a));
117 AWS_POSTCONDITION(aws_byte_buf_is_valid(b));
118 return rval;
119 }
120
aws_byte_buf_eq_c_str(const struct aws_byte_buf * const buf,const char * const c_str)121 bool aws_byte_buf_eq_c_str(const struct aws_byte_buf *const buf, const char *const c_str) {
122 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
123 AWS_PRECONDITION(c_str != NULL);
124 bool rval = aws_array_eq_c_str(buf->buffer, buf->len, c_str);
125 AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
126 return rval;
127 }
128
aws_byte_buf_eq_c_str_ignore_case(const struct aws_byte_buf * const buf,const char * const c_str)129 bool aws_byte_buf_eq_c_str_ignore_case(const struct aws_byte_buf *const buf, const char *const c_str) {
130 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
131 AWS_PRECONDITION(c_str != NULL);
132 bool rval = aws_array_eq_c_str_ignore_case(buf->buffer, buf->len, c_str);
133 AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
134 return rval;
135 }
136
aws_byte_buf_init_copy_from_cursor(struct aws_byte_buf * dest,struct aws_allocator * allocator,struct aws_byte_cursor src)137 int aws_byte_buf_init_copy_from_cursor(
138 struct aws_byte_buf *dest,
139 struct aws_allocator *allocator,
140 struct aws_byte_cursor src) {
141 AWS_PRECONDITION(allocator);
142 AWS_PRECONDITION(dest);
143 AWS_ERROR_PRECONDITION(aws_byte_cursor_is_valid(&src));
144
145 AWS_ZERO_STRUCT(*dest);
146
147 dest->buffer = (src.len > 0) ? (uint8_t *)aws_mem_acquire(allocator, src.len) : NULL;
148 if (src.len != 0 && dest->buffer == NULL) {
149 return AWS_OP_ERR;
150 }
151
152 dest->len = src.len;
153 dest->capacity = src.len;
154 dest->allocator = allocator;
155 if (src.len > 0) {
156 memcpy(dest->buffer, src.ptr, src.len);
157 }
158 AWS_POSTCONDITION(aws_byte_buf_is_valid(dest));
159 return AWS_OP_SUCCESS;
160 }
161
aws_byte_buf_init_cache_and_update_cursors(struct aws_byte_buf * dest,struct aws_allocator * allocator,...)162 int aws_byte_buf_init_cache_and_update_cursors(struct aws_byte_buf *dest, struct aws_allocator *allocator, ...) {
163 AWS_PRECONDITION(allocator);
164 AWS_PRECONDITION(dest);
165
166 AWS_ZERO_STRUCT(*dest);
167
168 size_t total_len = 0;
169 va_list args;
170 va_start(args, allocator);
171
172 /* Loop until final NULL arg is encountered */
173 struct aws_byte_cursor *cursor_i;
174 while ((cursor_i = va_arg(args, struct aws_byte_cursor *)) != NULL) {
175 AWS_ASSERT(aws_byte_cursor_is_valid(cursor_i));
176 if (aws_add_size_checked(total_len, cursor_i->len, &total_len)) {
177 return AWS_OP_ERR;
178 }
179 }
180 va_end(args);
181
182 if (aws_byte_buf_init(dest, allocator, total_len)) {
183 return AWS_OP_ERR;
184 }
185
186 va_start(args, allocator);
187 while ((cursor_i = va_arg(args, struct aws_byte_cursor *)) != NULL) {
188 /* Impossible for this call to fail, we pre-allocated sufficient space */
189 aws_byte_buf_append_and_update(dest, cursor_i);
190 }
191 va_end(args);
192
193 return AWS_OP_SUCCESS;
194 }
195
aws_byte_cursor_next_split(const struct aws_byte_cursor * AWS_RESTRICT input_str,char split_on,struct aws_byte_cursor * AWS_RESTRICT substr)196 bool aws_byte_cursor_next_split(
197 const struct aws_byte_cursor *AWS_RESTRICT input_str,
198 char split_on,
199 struct aws_byte_cursor *AWS_RESTRICT substr) {
200
201 AWS_PRECONDITION(aws_byte_cursor_is_valid(input_str));
202
203 /* If substr is zeroed-out, then this is the first run. */
204 const bool first_run = substr->ptr == NULL;
205
206 /* It's legal for input_str to be zeroed out: {.ptr=NULL, .len=0}
207 * Deal with this case separately */
208 if (AWS_UNLIKELY(input_str->ptr == NULL)) {
209 if (first_run) {
210 /* Set substr->ptr to something non-NULL so that next split() call doesn't look like the first run */
211 substr->ptr = (void *)"";
212 substr->len = 0;
213 return true;
214 }
215
216 /* done */
217 AWS_ZERO_STRUCT(*substr);
218 return false;
219 }
220
221 /* Rest of function deals with non-NULL input_str->ptr */
222
223 if (first_run) {
224 *substr = *input_str;
225 } else {
226 /* This is not the first run.
227 * Advance substr past the previous split. */
228 const uint8_t *input_end = input_str->ptr + input_str->len;
229 substr->ptr += substr->len + 1;
230
231 /* Note that it's ok if substr->ptr == input_end, this happens in the
232 * final valid split of an input_str that ends with the split_on character:
233 * Ex: "AB&" split on '&' produces "AB" and "" */
234 if (substr->ptr > input_end || substr->ptr < input_str->ptr) { /* 2nd check is overflow check */
235 /* done */
236 AWS_ZERO_STRUCT(*substr);
237 return false;
238 }
239
240 /* update len to be remainder of the string */
241 substr->len = input_str->len - (substr->ptr - input_str->ptr);
242 }
243
244 /* substr is now remainder of string, search for next split */
245 uint8_t *new_location = memchr(substr->ptr, split_on, substr->len);
246 if (new_location) {
247
248 /* Character found, update string length. */
249 substr->len = new_location - substr->ptr;
250 }
251
252 AWS_POSTCONDITION(aws_byte_cursor_is_valid(substr));
253 return true;
254 }
255
aws_byte_cursor_split_on_char_n(const struct aws_byte_cursor * AWS_RESTRICT input_str,char split_on,size_t n,struct aws_array_list * AWS_RESTRICT output)256 int aws_byte_cursor_split_on_char_n(
257 const struct aws_byte_cursor *AWS_RESTRICT input_str,
258 char split_on,
259 size_t n,
260 struct aws_array_list *AWS_RESTRICT output) {
261 AWS_ASSERT(aws_byte_cursor_is_valid(input_str));
262 AWS_ASSERT(output);
263 AWS_ASSERT(output->item_size >= sizeof(struct aws_byte_cursor));
264
265 size_t max_splits = n > 0 ? n : SIZE_MAX;
266 size_t split_count = 0;
267
268 struct aws_byte_cursor substr;
269 AWS_ZERO_STRUCT(substr);
270
271 /* Until we run out of substrs or hit the max split count, keep iterating and pushing into the array list. */
272 while (split_count <= max_splits && aws_byte_cursor_next_split(input_str, split_on, &substr)) {
273
274 if (split_count == max_splits) {
275 /* If this is the last split, take the rest of the string. */
276 substr.len = input_str->len - (substr.ptr - input_str->ptr);
277 }
278
279 if (AWS_UNLIKELY(aws_array_list_push_back(output, (const void *)&substr))) {
280 return AWS_OP_ERR;
281 }
282 ++split_count;
283 }
284
285 return AWS_OP_SUCCESS;
286 }
287
aws_byte_cursor_split_on_char(const struct aws_byte_cursor * AWS_RESTRICT input_str,char split_on,struct aws_array_list * AWS_RESTRICT output)288 int aws_byte_cursor_split_on_char(
289 const struct aws_byte_cursor *AWS_RESTRICT input_str,
290 char split_on,
291 struct aws_array_list *AWS_RESTRICT output) {
292
293 return aws_byte_cursor_split_on_char_n(input_str, split_on, 0, output);
294 }
295
aws_byte_cursor_find_exact(const struct aws_byte_cursor * AWS_RESTRICT input_str,const struct aws_byte_cursor * AWS_RESTRICT to_find,struct aws_byte_cursor * first_find)296 int aws_byte_cursor_find_exact(
297 const struct aws_byte_cursor *AWS_RESTRICT input_str,
298 const struct aws_byte_cursor *AWS_RESTRICT to_find,
299 struct aws_byte_cursor *first_find) {
300 if (to_find->len > input_str->len) {
301 return aws_raise_error(AWS_ERROR_STRING_MATCH_NOT_FOUND);
302 }
303
304 if (to_find->len < 1) {
305 return aws_raise_error(AWS_ERROR_SHORT_BUFFER);
306 }
307
308 struct aws_byte_cursor working_cur = *input_str;
309
310 while (working_cur.len) {
311 uint8_t *first_char_location = memchr(working_cur.ptr, (char)*to_find->ptr, working_cur.len);
312
313 if (!first_char_location) {
314 return aws_raise_error(AWS_ERROR_STRING_MATCH_NOT_FOUND);
315 }
316
317 aws_byte_cursor_advance(&working_cur, first_char_location - working_cur.ptr);
318
319 if (working_cur.len < to_find->len) {
320 return aws_raise_error(AWS_ERROR_STRING_MATCH_NOT_FOUND);
321 }
322
323 if (!memcmp(working_cur.ptr, to_find->ptr, to_find->len)) {
324 *first_find = working_cur;
325 return AWS_OP_SUCCESS;
326 }
327
328 aws_byte_cursor_advance(&working_cur, 1);
329 }
330
331 return aws_raise_error(AWS_ERROR_STRING_MATCH_NOT_FOUND);
332 }
333
aws_byte_buf_cat(struct aws_byte_buf * dest,size_t number_of_args,...)334 int aws_byte_buf_cat(struct aws_byte_buf *dest, size_t number_of_args, ...) {
335 AWS_PRECONDITION(aws_byte_buf_is_valid(dest));
336
337 va_list ap;
338 va_start(ap, number_of_args);
339
340 for (size_t i = 0; i < number_of_args; ++i) {
341 struct aws_byte_buf *buffer = va_arg(ap, struct aws_byte_buf *);
342 struct aws_byte_cursor cursor = aws_byte_cursor_from_buf(buffer);
343
344 if (aws_byte_buf_append(dest, &cursor)) {
345 va_end(ap);
346 AWS_POSTCONDITION(aws_byte_buf_is_valid(dest));
347 return AWS_OP_ERR;
348 }
349 }
350
351 va_end(ap);
352 AWS_POSTCONDITION(aws_byte_buf_is_valid(dest));
353 return AWS_OP_SUCCESS;
354 }
355
aws_byte_cursor_eq(const struct aws_byte_cursor * a,const struct aws_byte_cursor * b)356 bool aws_byte_cursor_eq(const struct aws_byte_cursor *a, const struct aws_byte_cursor *b) {
357 AWS_PRECONDITION(aws_byte_cursor_is_valid(a));
358 AWS_PRECONDITION(aws_byte_cursor_is_valid(b));
359 bool rv = aws_array_eq(a->ptr, a->len, b->ptr, b->len);
360 AWS_POSTCONDITION(aws_byte_cursor_is_valid(a));
361 AWS_POSTCONDITION(aws_byte_cursor_is_valid(b));
362 return rv;
363 }
364
aws_byte_cursor_eq_ignore_case(const struct aws_byte_cursor * a,const struct aws_byte_cursor * b)365 bool aws_byte_cursor_eq_ignore_case(const struct aws_byte_cursor *a, const struct aws_byte_cursor *b) {
366 AWS_PRECONDITION(aws_byte_cursor_is_valid(a));
367 AWS_PRECONDITION(aws_byte_cursor_is_valid(b));
368 bool rv = aws_array_eq_ignore_case(a->ptr, a->len, b->ptr, b->len);
369 AWS_POSTCONDITION(aws_byte_cursor_is_valid(a));
370 AWS_POSTCONDITION(aws_byte_cursor_is_valid(b));
371 return rv;
372 }
373
374 /* Every possible uint8_t value, lowercased */
375 static const uint8_t s_tolower_table[] = {
376 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
377 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
378 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 'a',
379 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
380 'x', 'y', 'z', 91, 92, 93, 94, 95, 96, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
381 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 123, 124, 125, 126, 127, 128, 129, 130, 131,
382 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153,
383 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
384 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197,
385 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
386 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,
387 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255};
388 AWS_STATIC_ASSERT(AWS_ARRAY_SIZE(s_tolower_table) == 256);
389
aws_lookup_table_to_lower_get(void)390 const uint8_t *aws_lookup_table_to_lower_get(void) {
391 return s_tolower_table;
392 }
393
aws_array_eq_ignore_case(const void * const array_a,const size_t len_a,const void * const array_b,const size_t len_b)394 bool aws_array_eq_ignore_case(
395 const void *const array_a,
396 const size_t len_a,
397 const void *const array_b,
398 const size_t len_b) {
399 AWS_PRECONDITION(
400 (len_a == 0) || AWS_MEM_IS_READABLE(array_a, len_a), "Input array [array_a] must be readable up to [len_a].");
401 AWS_PRECONDITION(
402 (len_b == 0) || AWS_MEM_IS_READABLE(array_b, len_b), "Input array [array_b] must be readable up to [len_b].");
403
404 if (len_a != len_b) {
405 return false;
406 }
407
408 const uint8_t *bytes_a = array_a;
409 const uint8_t *bytes_b = array_b;
410 for (size_t i = 0; i < len_a; ++i) {
411 if (s_tolower_table[bytes_a[i]] != s_tolower_table[bytes_b[i]]) {
412 return false;
413 }
414 }
415
416 return true;
417 }
418
aws_array_eq(const void * const array_a,const size_t len_a,const void * const array_b,const size_t len_b)419 bool aws_array_eq(const void *const array_a, const size_t len_a, const void *const array_b, const size_t len_b) {
420 AWS_PRECONDITION(
421 (len_a == 0) || AWS_MEM_IS_READABLE(array_a, len_a), "Input array [array_a] must be readable up to [len_a].");
422 AWS_PRECONDITION(
423 (len_b == 0) || AWS_MEM_IS_READABLE(array_b, len_b), "Input array [array_b] must be readable up to [len_b].");
424
425 if (len_a != len_b) {
426 return false;
427 }
428
429 if (len_a == 0) {
430 return true;
431 }
432
433 return !memcmp(array_a, array_b, len_a);
434 }
435
aws_array_eq_c_str_ignore_case(const void * const array,const size_t array_len,const char * const c_str)436 bool aws_array_eq_c_str_ignore_case(const void *const array, const size_t array_len, const char *const c_str) {
437 AWS_PRECONDITION(
438 array || (array_len == 0),
439 "Either input pointer [array_a] mustn't be NULL or input [array_len] mustn't be zero.");
440 AWS_PRECONDITION(c_str != NULL);
441
442 /* Simpler implementation could have been:
443 * return aws_array_eq_ignore_case(array, array_len, c_str, strlen(c_str));
444 * but that would have traversed c_str twice.
445 * This implementation traverses c_str just once. */
446
447 const uint8_t *array_bytes = array;
448 const uint8_t *str_bytes = (const uint8_t *)c_str;
449
450 for (size_t i = 0; i < array_len; ++i) {
451 uint8_t s = str_bytes[i];
452 if (s == '\0') {
453 return false;
454 }
455
456 if (s_tolower_table[array_bytes[i]] != s_tolower_table[s]) {
457 return false;
458 }
459 }
460
461 return str_bytes[array_len] == '\0';
462 }
463
aws_array_eq_c_str(const void * const array,const size_t array_len,const char * const c_str)464 bool aws_array_eq_c_str(const void *const array, const size_t array_len, const char *const c_str) {
465 AWS_PRECONDITION(
466 array || (array_len == 0),
467 "Either input pointer [array_a] mustn't be NULL or input [array_len] mustn't be zero.");
468 AWS_PRECONDITION(c_str != NULL);
469
470 /* Simpler implementation could have been:
471 * return aws_array_eq(array, array_len, c_str, strlen(c_str));
472 * but that would have traversed c_str twice.
473 * This implementation traverses c_str just once. */
474
475 const uint8_t *array_bytes = array;
476 const uint8_t *str_bytes = (const uint8_t *)c_str;
477
478 for (size_t i = 0; i < array_len; ++i) {
479 uint8_t s = str_bytes[i];
480 if (s == '\0') {
481 return false;
482 }
483
484 if (array_bytes[i] != s) {
485 return false;
486 }
487 }
488
489 return str_bytes[array_len] == '\0';
490 }
491
aws_hash_array_ignore_case(const void * array,const size_t len)492 uint64_t aws_hash_array_ignore_case(const void *array, const size_t len) {
493 AWS_PRECONDITION(AWS_MEM_IS_READABLE(array, len));
494 /* FNV-1a: https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function */
495 const uint64_t fnv_offset_basis = 0xcbf29ce484222325ULL;
496 const uint64_t fnv_prime = 0x100000001b3ULL;
497
498 const uint8_t *i = array;
499 const uint8_t *end = (i == NULL) ? NULL : (i + len);
500
501 uint64_t hash = fnv_offset_basis;
502 while (i != end) {
503 const uint8_t lower = s_tolower_table[*i++];
504 hash ^= lower;
505 #ifdef CBMC
506 # pragma CPROVER check push
507 # pragma CPROVER check disable "unsigned-overflow"
508 #endif
509 hash *= fnv_prime;
510 #ifdef CBMC
511 # pragma CPROVER check pop
512 #endif
513 }
514 return hash;
515 }
516
aws_hash_byte_cursor_ptr_ignore_case(const void * item)517 uint64_t aws_hash_byte_cursor_ptr_ignore_case(const void *item) {
518 AWS_PRECONDITION(aws_byte_cursor_is_valid(item));
519 const struct aws_byte_cursor *const cursor = item;
520 uint64_t rval = aws_hash_array_ignore_case(cursor->ptr, cursor->len);
521 AWS_POSTCONDITION(aws_byte_cursor_is_valid(item));
522 return rval;
523 }
524
aws_byte_cursor_eq_byte_buf(const struct aws_byte_cursor * const a,const struct aws_byte_buf * const b)525 bool aws_byte_cursor_eq_byte_buf(const struct aws_byte_cursor *const a, const struct aws_byte_buf *const b) {
526 AWS_PRECONDITION(aws_byte_cursor_is_valid(a));
527 AWS_PRECONDITION(aws_byte_buf_is_valid(b));
528 bool rv = aws_array_eq(a->ptr, a->len, b->buffer, b->len);
529 AWS_POSTCONDITION(aws_byte_cursor_is_valid(a));
530 AWS_POSTCONDITION(aws_byte_buf_is_valid(b));
531 return rv;
532 }
533
aws_byte_cursor_eq_byte_buf_ignore_case(const struct aws_byte_cursor * const a,const struct aws_byte_buf * const b)534 bool aws_byte_cursor_eq_byte_buf_ignore_case(
535 const struct aws_byte_cursor *const a,
536 const struct aws_byte_buf *const b) {
537 AWS_PRECONDITION(aws_byte_cursor_is_valid(a));
538 AWS_PRECONDITION(aws_byte_buf_is_valid(b));
539 bool rv = aws_array_eq_ignore_case(a->ptr, a->len, b->buffer, b->len);
540 AWS_POSTCONDITION(aws_byte_cursor_is_valid(a));
541 AWS_POSTCONDITION(aws_byte_buf_is_valid(b));
542 return rv;
543 }
544
aws_byte_cursor_eq_c_str(const struct aws_byte_cursor * const cursor,const char * const c_str)545 bool aws_byte_cursor_eq_c_str(const struct aws_byte_cursor *const cursor, const char *const c_str) {
546 AWS_PRECONDITION(aws_byte_cursor_is_valid(cursor));
547 AWS_PRECONDITION(c_str != NULL);
548 bool rv = aws_array_eq_c_str(cursor->ptr, cursor->len, c_str);
549 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cursor));
550 return rv;
551 }
552
aws_byte_cursor_eq_c_str_ignore_case(const struct aws_byte_cursor * const cursor,const char * const c_str)553 bool aws_byte_cursor_eq_c_str_ignore_case(const struct aws_byte_cursor *const cursor, const char *const c_str) {
554 AWS_PRECONDITION(aws_byte_cursor_is_valid(cursor));
555 AWS_PRECONDITION(c_str != NULL);
556 bool rv = aws_array_eq_c_str_ignore_case(cursor->ptr, cursor->len, c_str);
557 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cursor));
558 return rv;
559 }
560
aws_byte_buf_append(struct aws_byte_buf * to,const struct aws_byte_cursor * from)561 int aws_byte_buf_append(struct aws_byte_buf *to, const struct aws_byte_cursor *from) {
562 AWS_PRECONDITION(aws_byte_buf_is_valid(to));
563 AWS_PRECONDITION(aws_byte_cursor_is_valid(from));
564
565 if (to->capacity - to->len < from->len) {
566 AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
567 AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
568 return aws_raise_error(AWS_ERROR_DEST_COPY_TOO_SMALL);
569 }
570
571 if (from->len > 0) {
572 /* This assert teaches clang-tidy that from->ptr and to->buffer cannot be null in a non-empty buffers */
573 AWS_ASSERT(from->ptr);
574 AWS_ASSERT(to->buffer);
575 memcpy(to->buffer + to->len, from->ptr, from->len);
576 to->len += from->len;
577 }
578
579 AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
580 AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
581 return AWS_OP_SUCCESS;
582 }
583
aws_byte_buf_append_with_lookup(struct aws_byte_buf * AWS_RESTRICT to,const struct aws_byte_cursor * AWS_RESTRICT from,const uint8_t * lookup_table)584 int aws_byte_buf_append_with_lookup(
585 struct aws_byte_buf *AWS_RESTRICT to,
586 const struct aws_byte_cursor *AWS_RESTRICT from,
587 const uint8_t *lookup_table) {
588 AWS_PRECONDITION(aws_byte_buf_is_valid(to));
589 AWS_PRECONDITION(aws_byte_cursor_is_valid(from));
590 AWS_PRECONDITION(
591 AWS_MEM_IS_READABLE(lookup_table, 256), "Input array [lookup_table] must be at least 256 bytes long.");
592
593 if (to->capacity - to->len < from->len) {
594 AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
595 AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
596 return aws_raise_error(AWS_ERROR_DEST_COPY_TOO_SMALL);
597 }
598
599 for (size_t i = 0; i < from->len; ++i) {
600 to->buffer[to->len + i] = lookup_table[from->ptr[i]];
601 }
602
603 if (aws_add_size_checked(to->len, from->len, &to->len)) {
604 return AWS_OP_ERR;
605 }
606
607 AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
608 AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
609 return AWS_OP_SUCCESS;
610 }
611
s_aws_byte_buf_append_dynamic(struct aws_byte_buf * to,const struct aws_byte_cursor * from,bool clear_released_memory)612 static int s_aws_byte_buf_append_dynamic(
613 struct aws_byte_buf *to,
614 const struct aws_byte_cursor *from,
615 bool clear_released_memory) {
616 AWS_PRECONDITION(aws_byte_buf_is_valid(to));
617 AWS_PRECONDITION(aws_byte_cursor_is_valid(from));
618 AWS_ERROR_PRECONDITION(to->allocator);
619
620 if (to->capacity - to->len < from->len) {
621 /*
622 * NewCapacity = Max(OldCapacity * 2, OldCapacity + MissingCapacity)
623 */
624 size_t missing_capacity = from->len - (to->capacity - to->len);
625
626 size_t required_capacity = 0;
627 if (aws_add_size_checked(to->capacity, missing_capacity, &required_capacity)) {
628 AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
629 AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
630 return AWS_OP_ERR;
631 }
632
633 /*
634 * It's ok if this overflows, just clamp to max possible.
635 * In theory this lets us still grow a buffer that's larger than 1/2 size_t space
636 * at least enough to accommodate the append.
637 */
638 size_t growth_capacity = aws_add_size_saturating(to->capacity, to->capacity);
639
640 size_t new_capacity = required_capacity;
641 if (new_capacity < growth_capacity) {
642 new_capacity = growth_capacity;
643 }
644
645 /*
646 * Attempt to resize - we intentionally do not use reserve() in order to preserve
647 * the (unlikely) use case of from and to being the same buffer range.
648 */
649
650 /*
651 * Try the max, but if that fails and the required is smaller, try it in fallback
652 */
653 uint8_t *new_buffer = aws_mem_acquire(to->allocator, new_capacity);
654 if (new_buffer == NULL) {
655 if (new_capacity > required_capacity) {
656 new_capacity = required_capacity;
657 new_buffer = aws_mem_acquire(to->allocator, new_capacity);
658 if (new_buffer == NULL) {
659 AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
660 AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
661 return AWS_OP_ERR;
662 }
663 } else {
664 AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
665 AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
666 return AWS_OP_ERR;
667 }
668 }
669
670 /*
671 * Copy old buffer -> new buffer
672 */
673 if (to->len > 0) {
674 memcpy(new_buffer, to->buffer, to->len);
675 }
676 /*
677 * Copy what we actually wanted to append in the first place
678 */
679 if (from->len > 0) {
680 memcpy(new_buffer + to->len, from->ptr, from->len);
681 }
682
683 if (clear_released_memory) {
684 aws_secure_zero(to->buffer, to->capacity);
685 }
686
687 /*
688 * Get rid of the old buffer
689 */
690 aws_mem_release(to->allocator, to->buffer);
691
692 /*
693 * Switch to the new buffer
694 */
695 to->buffer = new_buffer;
696 to->capacity = new_capacity;
697 } else {
698 if (from->len > 0) {
699 /* This assert teaches clang-tidy that from->ptr and to->buffer cannot be null in a non-empty buffers */
700 AWS_ASSERT(from->ptr);
701 AWS_ASSERT(to->buffer);
702 memcpy(to->buffer + to->len, from->ptr, from->len);
703 }
704 }
705
706 to->len += from->len;
707
708 AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
709 AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
710 return AWS_OP_SUCCESS;
711 }
712
aws_byte_buf_append_dynamic(struct aws_byte_buf * to,const struct aws_byte_cursor * from)713 int aws_byte_buf_append_dynamic(struct aws_byte_buf *to, const struct aws_byte_cursor *from) {
714 return s_aws_byte_buf_append_dynamic(to, from, false);
715 }
716
aws_byte_buf_append_dynamic_secure(struct aws_byte_buf * to,const struct aws_byte_cursor * from)717 int aws_byte_buf_append_dynamic_secure(struct aws_byte_buf *to, const struct aws_byte_cursor *from) {
718 return s_aws_byte_buf_append_dynamic(to, from, true);
719 }
720
s_aws_byte_buf_append_byte_dynamic(struct aws_byte_buf * buffer,uint8_t value,bool clear_released_memory)721 static int s_aws_byte_buf_append_byte_dynamic(struct aws_byte_buf *buffer, uint8_t value, bool clear_released_memory) {
722 #if defined(_MSC_VER)
723 # pragma warning(push)
724 # pragma warning(disable : 4221)
725 #endif /* _MSC_VER */
726
727 /* msvc isn't a fan of this pointer-to-local assignment */
728 struct aws_byte_cursor eq_cursor = {.len = 1, .ptr = &value};
729
730 #if defined(_MSC_VER)
731 # pragma warning(pop)
732 #endif /* _MSC_VER */
733
734 return s_aws_byte_buf_append_dynamic(buffer, &eq_cursor, clear_released_memory);
735 }
736
aws_byte_buf_append_byte_dynamic(struct aws_byte_buf * buffer,uint8_t value)737 int aws_byte_buf_append_byte_dynamic(struct aws_byte_buf *buffer, uint8_t value) {
738 return s_aws_byte_buf_append_byte_dynamic(buffer, value, false);
739 }
740
aws_byte_buf_append_byte_dynamic_secure(struct aws_byte_buf * buffer,uint8_t value)741 int aws_byte_buf_append_byte_dynamic_secure(struct aws_byte_buf *buffer, uint8_t value) {
742 return s_aws_byte_buf_append_byte_dynamic(buffer, value, true);
743 }
744
aws_byte_buf_reserve(struct aws_byte_buf * buffer,size_t requested_capacity)745 int aws_byte_buf_reserve(struct aws_byte_buf *buffer, size_t requested_capacity) {
746 AWS_ERROR_PRECONDITION(buffer->allocator);
747 AWS_ERROR_PRECONDITION(aws_byte_buf_is_valid(buffer));
748
749 if (requested_capacity <= buffer->capacity) {
750 AWS_POSTCONDITION(aws_byte_buf_is_valid(buffer));
751 return AWS_OP_SUCCESS;
752 }
753 if (!buffer->buffer && !buffer->capacity && requested_capacity > buffer->capacity) {
754 if (aws_byte_buf_init(buffer, buffer->allocator, requested_capacity)) {
755 return AWS_OP_ERR;
756 }
757 AWS_POSTCONDITION(aws_byte_buf_is_valid(buffer));
758 return AWS_OP_SUCCESS;
759 }
760 if (aws_mem_realloc(buffer->allocator, (void **)&buffer->buffer, buffer->capacity, requested_capacity)) {
761 return AWS_OP_ERR;
762 }
763
764 buffer->capacity = requested_capacity;
765
766 AWS_POSTCONDITION(aws_byte_buf_is_valid(buffer));
767 return AWS_OP_SUCCESS;
768 }
769
aws_byte_buf_reserve_relative(struct aws_byte_buf * buffer,size_t additional_length)770 int aws_byte_buf_reserve_relative(struct aws_byte_buf *buffer, size_t additional_length) {
771 AWS_ERROR_PRECONDITION(buffer->allocator);
772 AWS_ERROR_PRECONDITION(aws_byte_buf_is_valid(buffer));
773
774 size_t requested_capacity = 0;
775 if (AWS_UNLIKELY(aws_add_size_checked(buffer->len, additional_length, &requested_capacity))) {
776 AWS_POSTCONDITION(aws_byte_buf_is_valid(buffer));
777 return AWS_OP_ERR;
778 }
779
780 return aws_byte_buf_reserve(buffer, requested_capacity);
781 }
782
aws_byte_cursor_right_trim_pred(const struct aws_byte_cursor * source,aws_byte_predicate_fn * predicate)783 struct aws_byte_cursor aws_byte_cursor_right_trim_pred(
784 const struct aws_byte_cursor *source,
785 aws_byte_predicate_fn *predicate) {
786 AWS_PRECONDITION(aws_byte_cursor_is_valid(source));
787 AWS_PRECONDITION(predicate != NULL);
788 struct aws_byte_cursor trimmed = *source;
789
790 while (trimmed.len > 0 && predicate(*(trimmed.ptr + trimmed.len - 1))) {
791 --trimmed.len;
792 }
793 AWS_POSTCONDITION(aws_byte_cursor_is_valid(source));
794 AWS_POSTCONDITION(aws_byte_cursor_is_valid(&trimmed));
795 return trimmed;
796 }
797
aws_byte_cursor_left_trim_pred(const struct aws_byte_cursor * source,aws_byte_predicate_fn * predicate)798 struct aws_byte_cursor aws_byte_cursor_left_trim_pred(
799 const struct aws_byte_cursor *source,
800 aws_byte_predicate_fn *predicate) {
801 AWS_PRECONDITION(aws_byte_cursor_is_valid(source));
802 AWS_PRECONDITION(predicate != NULL);
803 struct aws_byte_cursor trimmed = *source;
804
805 while (trimmed.len > 0 && predicate(*(trimmed.ptr))) {
806 --trimmed.len;
807 ++trimmed.ptr;
808 }
809 AWS_POSTCONDITION(aws_byte_cursor_is_valid(source));
810 AWS_POSTCONDITION(aws_byte_cursor_is_valid(&trimmed));
811 return trimmed;
812 }
813
aws_byte_cursor_trim_pred(const struct aws_byte_cursor * source,aws_byte_predicate_fn * predicate)814 struct aws_byte_cursor aws_byte_cursor_trim_pred(
815 const struct aws_byte_cursor *source,
816 aws_byte_predicate_fn *predicate) {
817 AWS_PRECONDITION(aws_byte_cursor_is_valid(source));
818 AWS_PRECONDITION(predicate != NULL);
819 struct aws_byte_cursor left_trimmed = aws_byte_cursor_left_trim_pred(source, predicate);
820 struct aws_byte_cursor dest = aws_byte_cursor_right_trim_pred(&left_trimmed, predicate);
821 AWS_POSTCONDITION(aws_byte_cursor_is_valid(source));
822 AWS_POSTCONDITION(aws_byte_cursor_is_valid(&dest));
823 return dest;
824 }
825
aws_byte_cursor_satisfies_pred(const struct aws_byte_cursor * source,aws_byte_predicate_fn * predicate)826 bool aws_byte_cursor_satisfies_pred(const struct aws_byte_cursor *source, aws_byte_predicate_fn *predicate) {
827 struct aws_byte_cursor trimmed = aws_byte_cursor_left_trim_pred(source, predicate);
828 bool rval = (trimmed.len == 0);
829 AWS_POSTCONDITION(aws_byte_cursor_is_valid(source));
830 return rval;
831 }
832
aws_byte_cursor_compare_lexical(const struct aws_byte_cursor * lhs,const struct aws_byte_cursor * rhs)833 int aws_byte_cursor_compare_lexical(const struct aws_byte_cursor *lhs, const struct aws_byte_cursor *rhs) {
834 AWS_PRECONDITION(aws_byte_cursor_is_valid(lhs));
835 AWS_PRECONDITION(aws_byte_cursor_is_valid(rhs));
836 /* make sure we don't pass NULL pointers to memcmp */
837 AWS_PRECONDITION(lhs->ptr != NULL);
838 AWS_PRECONDITION(rhs->ptr != NULL);
839 size_t comparison_length = lhs->len;
840 if (comparison_length > rhs->len) {
841 comparison_length = rhs->len;
842 }
843
844 int result = memcmp(lhs->ptr, rhs->ptr, comparison_length);
845
846 AWS_POSTCONDITION(aws_byte_cursor_is_valid(lhs));
847 AWS_POSTCONDITION(aws_byte_cursor_is_valid(rhs));
848 if (result != 0) {
849 return result;
850 }
851
852 if (lhs->len != rhs->len) {
853 return comparison_length == lhs->len ? -1 : 1;
854 }
855
856 return 0;
857 }
858
aws_byte_cursor_compare_lookup(const struct aws_byte_cursor * lhs,const struct aws_byte_cursor * rhs,const uint8_t * lookup_table)859 int aws_byte_cursor_compare_lookup(
860 const struct aws_byte_cursor *lhs,
861 const struct aws_byte_cursor *rhs,
862 const uint8_t *lookup_table) {
863 AWS_PRECONDITION(aws_byte_cursor_is_valid(lhs));
864 AWS_PRECONDITION(aws_byte_cursor_is_valid(rhs));
865 AWS_PRECONDITION(AWS_MEM_IS_READABLE(lookup_table, 256));
866 if (lhs->len == 0 && rhs->len == 0) {
867 return 0;
868 } else if (lhs->len == 0) {
869 return -1;
870 } else if (rhs->len == 0) {
871 return 1;
872 }
873 const uint8_t *lhs_curr = lhs->ptr;
874 const uint8_t *lhs_end = lhs_curr + lhs->len;
875
876 const uint8_t *rhs_curr = rhs->ptr;
877 const uint8_t *rhs_end = rhs_curr + rhs->len;
878
879 while (lhs_curr < lhs_end && rhs_curr < rhs_end) {
880 uint8_t lhc = lookup_table[*lhs_curr];
881 uint8_t rhc = lookup_table[*rhs_curr];
882
883 AWS_POSTCONDITION(aws_byte_cursor_is_valid(lhs));
884 AWS_POSTCONDITION(aws_byte_cursor_is_valid(rhs));
885 if (lhc < rhc) {
886 return -1;
887 }
888
889 if (lhc > rhc) {
890 return 1;
891 }
892
893 lhs_curr++;
894 rhs_curr++;
895 }
896
897 AWS_POSTCONDITION(aws_byte_cursor_is_valid(lhs));
898 AWS_POSTCONDITION(aws_byte_cursor_is_valid(rhs));
899 if (lhs_curr < lhs_end) {
900 return 1;
901 }
902
903 if (rhs_curr < rhs_end) {
904 return -1;
905 }
906
907 return 0;
908 }
909
910 /**
911 * For creating a byte buffer from a null-terminated string literal.
912 */
aws_byte_buf_from_c_str(const char * c_str)913 struct aws_byte_buf aws_byte_buf_from_c_str(const char *c_str) {
914 struct aws_byte_buf buf;
915 buf.len = (!c_str) ? 0 : strlen(c_str);
916 buf.capacity = buf.len;
917 buf.buffer = (buf.capacity == 0) ? NULL : (uint8_t *)c_str;
918 buf.allocator = NULL;
919 AWS_POSTCONDITION(aws_byte_buf_is_valid(&buf));
920 return buf;
921 }
922
aws_byte_buf_from_array(const void * bytes,size_t len)923 struct aws_byte_buf aws_byte_buf_from_array(const void *bytes, size_t len) {
924 AWS_PRECONDITION(AWS_MEM_IS_WRITABLE(bytes, len), "Input array [bytes] must be writable up to [len] bytes.");
925 struct aws_byte_buf buf;
926 buf.buffer = (len > 0) ? (uint8_t *)bytes : NULL;
927 buf.len = len;
928 buf.capacity = len;
929 buf.allocator = NULL;
930 AWS_POSTCONDITION(aws_byte_buf_is_valid(&buf));
931 return buf;
932 }
933
aws_byte_buf_from_empty_array(const void * bytes,size_t capacity)934 struct aws_byte_buf aws_byte_buf_from_empty_array(const void *bytes, size_t capacity) {
935 AWS_PRECONDITION(
936 AWS_MEM_IS_WRITABLE(bytes, capacity), "Input array [bytes] must be writable up to [capacity] bytes.");
937 struct aws_byte_buf buf;
938 buf.buffer = (capacity > 0) ? (uint8_t *)bytes : NULL;
939 buf.len = 0;
940 buf.capacity = capacity;
941 buf.allocator = NULL;
942 AWS_POSTCONDITION(aws_byte_buf_is_valid(&buf));
943 return buf;
944 }
945
aws_byte_cursor_from_buf(const struct aws_byte_buf * const buf)946 struct aws_byte_cursor aws_byte_cursor_from_buf(const struct aws_byte_buf *const buf) {
947 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
948 struct aws_byte_cursor cur;
949 cur.ptr = buf->buffer;
950 cur.len = buf->len;
951 AWS_POSTCONDITION(aws_byte_cursor_is_valid(&cur));
952 return cur;
953 }
954
aws_byte_cursor_from_c_str(const char * c_str)955 struct aws_byte_cursor aws_byte_cursor_from_c_str(const char *c_str) {
956 struct aws_byte_cursor cur;
957 cur.ptr = (uint8_t *)c_str;
958 cur.len = (cur.ptr) ? strlen(c_str) : 0;
959 AWS_POSTCONDITION(aws_byte_cursor_is_valid(&cur));
960 return cur;
961 }
962
aws_byte_cursor_from_array(const void * const bytes,const size_t len)963 struct aws_byte_cursor aws_byte_cursor_from_array(const void *const bytes, const size_t len) {
964 AWS_PRECONDITION(len == 0 || AWS_MEM_IS_READABLE(bytes, len), "Input array [bytes] must be readable up to [len].");
965 struct aws_byte_cursor cur;
966 cur.ptr = (uint8_t *)bytes;
967 cur.len = len;
968 AWS_POSTCONDITION(aws_byte_cursor_is_valid(&cur));
969 return cur;
970 }
971
972 #ifdef CBMC
973 # pragma CPROVER check push
974 # pragma CPROVER check disable "unsigned-overflow"
975 #endif
976 /**
977 * If index >= bound, bound > (SIZE_MAX / 2), or index > (SIZE_MAX / 2), returns
978 * 0. Otherwise, returns UINTPTR_MAX. This function is designed to return the correct
979 * value even under CPU speculation conditions, and is intended to be used for
980 * SPECTRE mitigation purposes.
981 */
aws_nospec_mask(size_t index,size_t bound)982 size_t aws_nospec_mask(size_t index, size_t bound) {
983 /*
984 * SPECTRE mitigation - we compute a mask that will be zero if len < 0
985 * or len >= buf->len, and all-ones otherwise, and AND it into the index.
986 * It is critical that we avoid any branches in this logic.
987 */
988
989 /*
990 * Hide the index value from the optimizer. This helps ensure that all this
991 * logic doesn't get eliminated.
992 */
993 #if defined(__GNUC__) || defined(__clang__)
994 __asm__ __volatile__("" : "+r"(index));
995 #endif
996 #if defined(_MSVC_LANG)
997 /*
998 * MSVC doesn't have a good way for us to blind the optimizer, and doesn't
999 * even have inline asm on x64. Some experimentation indicates that this
1000 * hack seems to confuse it sufficiently for our needs.
1001 */
1002 *((volatile uint8_t *)&index) += 0;
1003 #endif
1004
1005 /*
1006 * If len > (SIZE_MAX / 2), then we can end up with len - buf->len being
1007 * positive simply because the sign bit got inverted away. So we also check
1008 * that the sign bit isn't set from the start.
1009 *
1010 * We also check that bound <= (SIZE_MAX / 2) to catch cases where the
1011 * buffer is _already_ out of bounds.
1012 */
1013 size_t negative_mask = index | bound;
1014 size_t toobig_mask = bound - index - (uintptr_t)1;
1015 size_t combined_mask = negative_mask | toobig_mask;
1016
1017 /*
1018 * combined_mask needs to have its sign bit OFF for us to be in range.
1019 * We'd like to expand this to a mask we can AND into our index, so flip
1020 * that bit (and everything else), shift it over so it's the only bit in the
1021 * ones position, and multiply across the entire register.
1022 *
1023 * First, extract the (inverse) top bit and move it to the lowest bit.
1024 * Because there's no standard SIZE_BIT in C99, we'll divide by a mask with
1025 * just the top bit set instead.
1026 */
1027
1028 combined_mask = (~combined_mask) / (SIZE_MAX - (SIZE_MAX >> 1));
1029
1030 /*
1031 * Now multiply it to replicate it across all bits.
1032 *
1033 * Note that GCC is smart enough to optimize the divide-and-multiply into
1034 * an arithmetic right shift operation on x86.
1035 */
1036 combined_mask = combined_mask * UINTPTR_MAX;
1037
1038 return combined_mask;
1039 }
1040 #ifdef CBMC
1041 # pragma CPROVER check pop
1042 #endif
1043
1044 /**
1045 * Tests if the given aws_byte_cursor has at least len bytes remaining. If so,
1046 * *buf is advanced by len bytes (incrementing ->ptr and decrementing ->len),
1047 * and an aws_byte_cursor referring to the first len bytes of the original *buf
1048 * is returned. Otherwise, an aws_byte_cursor with ->ptr = NULL, ->len = 0 is
1049 * returned.
1050 *
1051 * Note that if len is above (SIZE_MAX / 2), this function will also treat it as
1052 * a buffer overflow, and return NULL without changing *buf.
1053 */
aws_byte_cursor_advance(struct aws_byte_cursor * const cursor,const size_t len)1054 struct aws_byte_cursor aws_byte_cursor_advance(struct aws_byte_cursor *const cursor, const size_t len) {
1055 AWS_PRECONDITION(aws_byte_cursor_is_valid(cursor));
1056 struct aws_byte_cursor rv;
1057 if (cursor->len > (SIZE_MAX >> 1) || len > (SIZE_MAX >> 1) || len > cursor->len) {
1058 rv.ptr = NULL;
1059 rv.len = 0;
1060 } else {
1061 rv.ptr = cursor->ptr;
1062 rv.len = len;
1063 cursor->ptr = (cursor->ptr == NULL) ? NULL : cursor->ptr + len;
1064 cursor->len -= len;
1065 }
1066 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cursor));
1067 AWS_POSTCONDITION(aws_byte_cursor_is_valid(&rv));
1068 return rv;
1069 }
1070
1071 /**
1072 * Behaves identically to aws_byte_cursor_advance, but avoids speculative
1073 * execution potentially reading out-of-bounds pointers (by returning an
1074 * empty ptr in such speculated paths).
1075 *
1076 * This should generally be done when using an untrusted or
1077 * data-dependent value for 'len', to avoid speculating into a path where
1078 * cursor->ptr points outside the true ptr length.
1079 */
1080
aws_byte_cursor_advance_nospec(struct aws_byte_cursor * const cursor,size_t len)1081 struct aws_byte_cursor aws_byte_cursor_advance_nospec(struct aws_byte_cursor *const cursor, size_t len) {
1082 AWS_PRECONDITION(aws_byte_cursor_is_valid(cursor));
1083
1084 struct aws_byte_cursor rv;
1085
1086 if (len <= cursor->len && len <= (SIZE_MAX >> 1) && cursor->len <= (SIZE_MAX >> 1)) {
1087 /*
1088 * If we're speculating past a failed bounds check, null out the pointer. This ensures
1089 * that we don't try to read past the end of the buffer and leak information about other
1090 * memory through timing side-channels.
1091 */
1092 uintptr_t mask = aws_nospec_mask(len, cursor->len + 1);
1093
1094 /* Make sure we don't speculate-underflow len either */
1095 len = len & mask;
1096 cursor->ptr = (uint8_t *)((uintptr_t)cursor->ptr & mask);
1097 /* Make sure subsequent nospec accesses don't advance ptr past NULL */
1098 cursor->len = cursor->len & mask;
1099
1100 rv.ptr = cursor->ptr;
1101 /* Make sure anything acting upon the returned cursor _also_ doesn't advance past NULL */
1102 rv.len = len & mask;
1103
1104 cursor->ptr = (cursor->ptr == NULL) ? NULL : cursor->ptr + len;
1105 cursor->len -= len;
1106 } else {
1107 rv.ptr = NULL;
1108 rv.len = 0;
1109 }
1110
1111 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cursor));
1112 AWS_POSTCONDITION(aws_byte_cursor_is_valid(&rv));
1113 return rv;
1114 }
1115
1116 /**
1117 * Reads specified length of data from byte cursor and copies it to the
1118 * destination array.
1119 *
1120 * On success, returns true and updates the cursor pointer/length accordingly.
1121 * If there is insufficient space in the cursor, returns false, leaving the
1122 * cursor unchanged.
1123 */
aws_byte_cursor_read(struct aws_byte_cursor * AWS_RESTRICT cur,void * AWS_RESTRICT dest,const size_t len)1124 bool aws_byte_cursor_read(struct aws_byte_cursor *AWS_RESTRICT cur, void *AWS_RESTRICT dest, const size_t len) {
1125 AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1126 AWS_PRECONDITION(AWS_MEM_IS_WRITABLE(dest, len));
1127 if (len == 0) {
1128 return true;
1129 }
1130
1131 struct aws_byte_cursor slice = aws_byte_cursor_advance_nospec(cur, len);
1132
1133 if (slice.ptr) {
1134 memcpy(dest, slice.ptr, len);
1135 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1136 AWS_POSTCONDITION(AWS_MEM_IS_READABLE(dest, len));
1137 return true;
1138 }
1139 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1140 return false;
1141 }
1142
1143 /**
1144 * Reads as many bytes from cursor as size of buffer, and copies them to buffer.
1145 *
1146 * On success, returns true and updates the cursor pointer/length accordingly.
1147 * If there is insufficient space in the cursor, returns false, leaving the
1148 * cursor unchanged.
1149 */
aws_byte_cursor_read_and_fill_buffer(struct aws_byte_cursor * AWS_RESTRICT cur,struct aws_byte_buf * AWS_RESTRICT dest)1150 bool aws_byte_cursor_read_and_fill_buffer(
1151 struct aws_byte_cursor *AWS_RESTRICT cur,
1152 struct aws_byte_buf *AWS_RESTRICT dest) {
1153 AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1154 AWS_PRECONDITION(aws_byte_buf_is_valid(dest));
1155 if (aws_byte_cursor_read(cur, dest->buffer, dest->capacity)) {
1156 dest->len = dest->capacity;
1157 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1158 AWS_POSTCONDITION(aws_byte_buf_is_valid(dest));
1159 return true;
1160 }
1161 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1162 AWS_POSTCONDITION(aws_byte_buf_is_valid(dest));
1163 return false;
1164 }
1165
1166 /**
1167 * Reads a single byte from cursor, placing it in *var.
1168 *
1169 * On success, returns true and updates the cursor pointer/length accordingly.
1170 * If there is insufficient space in the cursor, returns false, leaving the
1171 * cursor unchanged.
1172 */
aws_byte_cursor_read_u8(struct aws_byte_cursor * AWS_RESTRICT cur,uint8_t * AWS_RESTRICT var)1173 bool aws_byte_cursor_read_u8(struct aws_byte_cursor *AWS_RESTRICT cur, uint8_t *AWS_RESTRICT var) {
1174 AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1175 AWS_PRECONDITION(AWS_MEM_IS_WRITABLE(var, 1));
1176 bool rv = aws_byte_cursor_read(cur, var, 1);
1177 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1178 return rv;
1179 }
1180
1181 /**
1182 * Reads a 16-bit value in network byte order from cur, and places it in host
1183 * byte order into var.
1184 *
1185 * On success, returns true and updates the cursor pointer/length accordingly.
1186 * If there is insufficient space in the cursor, returns false, leaving the
1187 * cursor unchanged.
1188 */
aws_byte_cursor_read_be16(struct aws_byte_cursor * cur,uint16_t * var)1189 bool aws_byte_cursor_read_be16(struct aws_byte_cursor *cur, uint16_t *var) {
1190 AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1191 AWS_PRECONDITION(AWS_OBJECT_PTR_IS_WRITABLE(var));
1192 bool rv = aws_byte_cursor_read(cur, var, 2);
1193
1194 if (AWS_LIKELY(rv)) {
1195 *var = aws_ntoh16(*var);
1196 }
1197
1198 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1199 return rv;
1200 }
1201
1202 /**
1203 * Reads an unsigned 24-bit value (3 bytes) in network byte order from cur,
1204 * and places it in host byte order into 32-bit var.
1205 * Ex: if cur's next 3 bytes are {0xAA, 0xBB, 0xCC}, then var becomes 0x00AABBCC.
1206 *
1207 * On success, returns true and updates the cursor pointer/length accordingly.
1208 * If there is insufficient space in the cursor, returns false, leaving the
1209 * cursor unchanged.
1210 */
aws_byte_cursor_read_be24(struct aws_byte_cursor * cur,uint32_t * var)1211 bool aws_byte_cursor_read_be24(struct aws_byte_cursor *cur, uint32_t *var) {
1212 AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1213 AWS_PRECONDITION(AWS_OBJECT_PTR_IS_WRITABLE(var));
1214
1215 uint8_t *var_bytes = (void *)var;
1216
1217 /* read into "lower" 3 bytes */
1218 bool rv = aws_byte_cursor_read(cur, &var_bytes[1], 3);
1219
1220 if (AWS_LIKELY(rv)) {
1221 /* zero out "highest" 4th byte*/
1222 var_bytes[0] = 0;
1223
1224 *var = aws_ntoh32(*var);
1225 }
1226
1227 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1228 return rv;
1229 }
1230
1231 /**
1232 * Reads a 32-bit value in network byte order from cur, and places it in host
1233 * byte order into var.
1234 *
1235 * On success, returns true and updates the cursor pointer/length accordingly.
1236 * If there is insufficient space in the cursor, returns false, leaving the
1237 * cursor unchanged.
1238 */
aws_byte_cursor_read_be32(struct aws_byte_cursor * cur,uint32_t * var)1239 bool aws_byte_cursor_read_be32(struct aws_byte_cursor *cur, uint32_t *var) {
1240 AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1241 AWS_PRECONDITION(AWS_OBJECT_PTR_IS_WRITABLE(var));
1242 bool rv = aws_byte_cursor_read(cur, var, 4);
1243
1244 if (AWS_LIKELY(rv)) {
1245 *var = aws_ntoh32(*var);
1246 }
1247
1248 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1249 return rv;
1250 }
1251
1252 /**
1253 * Reads a 32-bit value in network byte order from cur, and places it in host
1254 * byte order into var.
1255 *
1256 * On success, returns true and updates the cursor pointer/length accordingly.
1257 * If there is insufficient space in the cursor, returns false, leaving the
1258 * cursor unchanged.
1259 */
aws_byte_cursor_read_float_be32(struct aws_byte_cursor * cur,float * var)1260 bool aws_byte_cursor_read_float_be32(struct aws_byte_cursor *cur, float *var) {
1261 AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1262 AWS_PRECONDITION(AWS_OBJECT_PTR_IS_WRITABLE(var));
1263 bool rv = aws_byte_cursor_read(cur, var, sizeof(float));
1264
1265 if (AWS_LIKELY(rv)) {
1266 *var = aws_ntohf32(*var);
1267 }
1268
1269 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1270 return rv;
1271 }
1272
1273 /**
1274 * Reads a 64-bit value in network byte order from cur, and places it in host
1275 * byte order into var.
1276 *
1277 * On success, returns true and updates the cursor pointer/length accordingly.
1278 * If there is insufficient space in the cursor, returns false, leaving the
1279 * cursor unchanged.
1280 */
aws_byte_cursor_read_float_be64(struct aws_byte_cursor * cur,double * var)1281 bool aws_byte_cursor_read_float_be64(struct aws_byte_cursor *cur, double *var) {
1282 AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1283 AWS_PRECONDITION(AWS_OBJECT_PTR_IS_WRITABLE(var));
1284 bool rv = aws_byte_cursor_read(cur, var, sizeof(double));
1285
1286 if (AWS_LIKELY(rv)) {
1287 *var = aws_ntohf64(*var);
1288 }
1289
1290 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1291 return rv;
1292 }
1293
1294 /**
1295 * Reads a 64-bit value in network byte order from cur, and places it in host
1296 * byte order into var.
1297 *
1298 * On success, returns true and updates the cursor pointer/length accordingly.
1299 * If there is insufficient space in the cursor, returns false, leaving the
1300 * cursor unchanged.
1301 */
aws_byte_cursor_read_be64(struct aws_byte_cursor * cur,uint64_t * var)1302 bool aws_byte_cursor_read_be64(struct aws_byte_cursor *cur, uint64_t *var) {
1303 AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1304 AWS_PRECONDITION(AWS_OBJECT_PTR_IS_WRITABLE(var));
1305 bool rv = aws_byte_cursor_read(cur, var, sizeof(*var));
1306
1307 if (AWS_LIKELY(rv)) {
1308 *var = aws_ntoh64(*var);
1309 }
1310
1311 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1312 return rv;
1313 }
1314
1315 /* Lookup from '0' -> 0, 'f' -> 0xf, 'F' -> 0xF, etc
1316 * invalid characters have value 255 */
1317 /* clang-format off */
1318 static const uint8_t s_hex_to_num_table[] = {
1319 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1320 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1321 255, 255,
1322 /* 0 - 9 */
1323 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
1324 255, 255, 255, 255, 255, 255, 255,
1325 /* A - F */
1326 0xA, 0xB, 0xC, 0xD, 0xE, 0xF,
1327 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1328 255, 255, 255,
1329 /* a - f */
1330 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
1331 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1332 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1333 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1334 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1335 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1336 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1337 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1338 };
1339 AWS_STATIC_ASSERT(AWS_ARRAY_SIZE(s_hex_to_num_table) == 256);
1340 /* clang-format on */
1341
aws_lookup_table_hex_to_num_get(void)1342 const uint8_t *aws_lookup_table_hex_to_num_get(void) {
1343 return s_hex_to_num_table;
1344 }
1345
aws_byte_cursor_read_hex_u8(struct aws_byte_cursor * cur,uint8_t * var)1346 bool aws_byte_cursor_read_hex_u8(struct aws_byte_cursor *cur, uint8_t *var) {
1347 AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1348 AWS_PRECONDITION(AWS_OBJECT_PTR_IS_WRITABLE(var));
1349
1350 bool success = false;
1351 if (AWS_LIKELY(cur->len >= 2)) {
1352 const uint8_t hi = s_hex_to_num_table[cur->ptr[0]];
1353 const uint8_t lo = s_hex_to_num_table[cur->ptr[1]];
1354
1355 /* table maps invalid characters to 255 */
1356 if (AWS_LIKELY(hi != 255 && lo != 255)) {
1357 *var = (hi << 4) | lo;
1358 cur->ptr += 2;
1359 cur->len -= 2;
1360 success = true;
1361 }
1362 }
1363
1364 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1365 return success;
1366 }
1367
1368 /**
1369 * Appends a sub-buffer to the specified buffer.
1370 *
1371 * If the buffer has at least `len' bytes remaining (buffer->capacity - buffer->len >= len),
1372 * then buffer->len is incremented by len, and an aws_byte_buf is assigned to *output corresponding
1373 * to the last len bytes of the input buffer. The aws_byte_buf at *output will have a null
1374 * allocator, a zero initial length, and a capacity of 'len'. The function then returns true.
1375 *
1376 * If there is insufficient space, then this function nulls all fields in *output and returns
1377 * false.
1378 */
aws_byte_buf_advance(struct aws_byte_buf * const AWS_RESTRICT buffer,struct aws_byte_buf * const AWS_RESTRICT output,const size_t len)1379 bool aws_byte_buf_advance(
1380 struct aws_byte_buf *const AWS_RESTRICT buffer,
1381 struct aws_byte_buf *const AWS_RESTRICT output,
1382 const size_t len) {
1383 AWS_PRECONDITION(aws_byte_buf_is_valid(buffer));
1384 AWS_PRECONDITION(aws_byte_buf_is_valid(output));
1385 if (buffer->capacity - buffer->len >= len) {
1386 *output = aws_byte_buf_from_array((buffer->buffer == NULL) ? NULL : buffer->buffer + buffer->len, len);
1387 buffer->len += len;
1388 output->len = 0;
1389 AWS_POSTCONDITION(aws_byte_buf_is_valid(buffer));
1390 AWS_POSTCONDITION(aws_byte_buf_is_valid(output));
1391 return true;
1392 } else {
1393 AWS_ZERO_STRUCT(*output);
1394 AWS_POSTCONDITION(aws_byte_buf_is_valid(buffer));
1395 AWS_POSTCONDITION(aws_byte_buf_is_valid(output));
1396 return false;
1397 }
1398 }
1399
1400 /**
1401 * Write specified number of bytes from array to byte buffer.
1402 *
1403 * On success, returns true and updates the buffer length accordingly.
1404 * If there is insufficient space in the buffer, returns false, leaving the
1405 * buffer unchanged.
1406 */
aws_byte_buf_write(struct aws_byte_buf * AWS_RESTRICT buf,const uint8_t * AWS_RESTRICT src,size_t len)1407 bool aws_byte_buf_write(struct aws_byte_buf *AWS_RESTRICT buf, const uint8_t *AWS_RESTRICT src, size_t len) {
1408 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1409 AWS_PRECONDITION(AWS_MEM_IS_READABLE(src, len), "Input array [src] must be readable up to [len] bytes.");
1410
1411 if (len == 0) {
1412 AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
1413 return true;
1414 }
1415
1416 if (buf->len > (SIZE_MAX >> 1) || len > (SIZE_MAX >> 1) || buf->len + len > buf->capacity) {
1417 AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
1418 return false;
1419 }
1420
1421 memcpy(buf->buffer + buf->len, src, len);
1422 buf->len += len;
1423
1424 AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
1425 return true;
1426 }
1427
1428 /**
1429 * Copies all bytes from buffer to buffer.
1430 *
1431 * On success, returns true and updates the buffer /length accordingly.
1432 * If there is insufficient space in the buffer, returns false, leaving the
1433 * buffer unchanged.
1434 */
aws_byte_buf_write_from_whole_buffer(struct aws_byte_buf * AWS_RESTRICT buf,struct aws_byte_buf src)1435 bool aws_byte_buf_write_from_whole_buffer(struct aws_byte_buf *AWS_RESTRICT buf, struct aws_byte_buf src) {
1436 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1437 AWS_PRECONDITION(aws_byte_buf_is_valid(&src));
1438 return aws_byte_buf_write(buf, src.buffer, src.len);
1439 }
1440
1441 /**
1442 * Copies all bytes from buffer to buffer.
1443 *
1444 * On success, returns true and updates the buffer /length accordingly.
1445 * If there is insufficient space in the buffer, returns false, leaving the
1446 * buffer unchanged.
1447 */
aws_byte_buf_write_from_whole_cursor(struct aws_byte_buf * AWS_RESTRICT buf,struct aws_byte_cursor src)1448 bool aws_byte_buf_write_from_whole_cursor(struct aws_byte_buf *AWS_RESTRICT buf, struct aws_byte_cursor src) {
1449 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1450 AWS_PRECONDITION(aws_byte_cursor_is_valid(&src));
1451 return aws_byte_buf_write(buf, src.ptr, src.len);
1452 }
1453
aws_byte_buf_write_to_capacity(struct aws_byte_buf * buf,struct aws_byte_cursor * advancing_cursor)1454 struct aws_byte_cursor aws_byte_buf_write_to_capacity(
1455 struct aws_byte_buf *buf,
1456 struct aws_byte_cursor *advancing_cursor) {
1457
1458 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1459 AWS_PRECONDITION(aws_byte_cursor_is_valid(advancing_cursor));
1460
1461 size_t available = buf->capacity - buf->len;
1462 size_t write_size = aws_min_size(available, advancing_cursor->len);
1463 struct aws_byte_cursor write_cursor = aws_byte_cursor_advance(advancing_cursor, write_size);
1464 aws_byte_buf_write_from_whole_cursor(buf, write_cursor);
1465 return write_cursor;
1466 }
1467
1468 /**
1469 * Copies one byte to buffer.
1470 *
1471 * On success, returns true and updates the cursor /length
1472 accordingly.
1473
1474 * If there is insufficient space in the cursor, returns false, leaving the
1475 cursor unchanged.
1476 */
aws_byte_buf_write_u8(struct aws_byte_buf * AWS_RESTRICT buf,uint8_t c)1477 bool aws_byte_buf_write_u8(struct aws_byte_buf *AWS_RESTRICT buf, uint8_t c) {
1478 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1479 return aws_byte_buf_write(buf, &c, 1);
1480 }
1481
1482 /**
1483 * Writes one byte repeatedly to buffer (like memset)
1484 *
1485 * If there is insufficient space in the buffer, returns false, leaving the
1486 * buffer unchanged.
1487 */
aws_byte_buf_write_u8_n(struct aws_byte_buf * buf,uint8_t c,size_t count)1488 bool aws_byte_buf_write_u8_n(struct aws_byte_buf *buf, uint8_t c, size_t count) {
1489 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1490
1491 if (buf->len > (SIZE_MAX >> 1) || count > (SIZE_MAX >> 1) || buf->len + count > buf->capacity) {
1492 AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
1493 return false;
1494 }
1495
1496 memset(buf->buffer + buf->len, c, count);
1497 buf->len += count;
1498
1499 AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
1500 return true;
1501 }
1502
1503 /**
1504 * Writes a 16-bit integer in network byte order (big endian) to buffer.
1505 *
1506 * On success, returns true and updates the cursor /length accordingly.
1507 * If there is insufficient space in the cursor, returns false, leaving the
1508 * cursor unchanged.
1509 */
aws_byte_buf_write_be16(struct aws_byte_buf * buf,uint16_t x)1510 bool aws_byte_buf_write_be16(struct aws_byte_buf *buf, uint16_t x) {
1511 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1512 x = aws_hton16(x);
1513 return aws_byte_buf_write(buf, (uint8_t *)&x, 2);
1514 }
1515
1516 /**
1517 * Writes low 24-bits (3 bytes) of an unsigned integer in network byte order (big endian) to buffer.
1518 * Ex: If x is 0x00AABBCC then {0xAA, 0xBB, 0xCC} is written to buffer.
1519 *
1520 * On success, returns true and updates the buffer /length accordingly.
1521 * If there is insufficient space in the buffer, or x's value cannot fit in 3 bytes,
1522 * returns false, leaving the buffer unchanged.
1523 */
aws_byte_buf_write_be24(struct aws_byte_buf * buf,uint32_t x)1524 bool aws_byte_buf_write_be24(struct aws_byte_buf *buf, uint32_t x) {
1525 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1526
1527 if (x > 0x00FFFFFF) {
1528 return false;
1529 }
1530
1531 uint32_t be32 = aws_hton32(x);
1532 uint8_t *be32_bytes = (uint8_t *)&be32;
1533
1534 /* write "lower" 3 bytes */
1535 return aws_byte_buf_write(buf, &be32_bytes[1], 3);
1536 }
1537
1538 /**
1539 * Writes a 32-bit integer in network byte order (big endian) to buffer.
1540 *
1541 * On success, returns true and updates the cursor /length accordingly.
1542 * If there is insufficient space in the cursor, returns false, leaving the
1543 * cursor unchanged.
1544 */
aws_byte_buf_write_be32(struct aws_byte_buf * buf,uint32_t x)1545 bool aws_byte_buf_write_be32(struct aws_byte_buf *buf, uint32_t x) {
1546 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1547 x = aws_hton32(x);
1548 return aws_byte_buf_write(buf, (uint8_t *)&x, 4);
1549 }
1550
1551 /**
1552 * Writes a 32-bit float in network byte order (big endian) to buffer.
1553 *
1554 * On success, returns true and updates the cursor /length accordingly.
1555 * If there is insufficient space in the cursor, returns false, leaving the
1556 * cursor unchanged.
1557 */
aws_byte_buf_write_float_be32(struct aws_byte_buf * buf,float x)1558 bool aws_byte_buf_write_float_be32(struct aws_byte_buf *buf, float x) {
1559 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1560 x = aws_htonf32(x);
1561 return aws_byte_buf_write(buf, (uint8_t *)&x, 4);
1562 }
1563
1564 /**
1565 * Writes a 64-bit integer in network byte order (big endian) to buffer.
1566 *
1567 * On success, returns true and updates the cursor /length accordingly.
1568 * If there is insufficient space in the cursor, returns false, leaving the
1569 * cursor unchanged.
1570 */
aws_byte_buf_write_be64(struct aws_byte_buf * buf,uint64_t x)1571 bool aws_byte_buf_write_be64(struct aws_byte_buf *buf, uint64_t x) {
1572 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1573 x = aws_hton64(x);
1574 return aws_byte_buf_write(buf, (uint8_t *)&x, 8);
1575 }
1576
1577 /**
1578 * Writes a 64-bit float in network byte order (big endian) to buffer.
1579 *
1580 * On success, returns true and updates the cursor /length accordingly.
1581 * If there is insufficient space in the cursor, returns false, leaving the
1582 * cursor unchanged.
1583 */
aws_byte_buf_write_float_be64(struct aws_byte_buf * buf,double x)1584 bool aws_byte_buf_write_float_be64(struct aws_byte_buf *buf, double x) {
1585 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1586 x = aws_htonf64(x);
1587 return aws_byte_buf_write(buf, (uint8_t *)&x, 8);
1588 }
1589
aws_byte_buf_append_and_update(struct aws_byte_buf * to,struct aws_byte_cursor * from_and_update)1590 int aws_byte_buf_append_and_update(struct aws_byte_buf *to, struct aws_byte_cursor *from_and_update) {
1591 AWS_PRECONDITION(aws_byte_buf_is_valid(to));
1592 AWS_PRECONDITION(aws_byte_cursor_is_valid(from_and_update));
1593
1594 if (aws_byte_buf_append(to, from_and_update)) {
1595 return AWS_OP_ERR;
1596 }
1597
1598 from_and_update->ptr = to->buffer + (to->len - from_and_update->len);
1599 return AWS_OP_SUCCESS;
1600 }
1601
1602 static struct aws_byte_cursor s_null_terminator_cursor = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("\0");
aws_byte_buf_append_null_terminator(struct aws_byte_buf * buf)1603 int aws_byte_buf_append_null_terminator(struct aws_byte_buf *buf) {
1604 return aws_byte_buf_append_dynamic(buf, &s_null_terminator_cursor);
1605 }
1606
aws_isalnum(uint8_t ch)1607 bool aws_isalnum(uint8_t ch) {
1608 return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9');
1609 }
1610
aws_isalpha(uint8_t ch)1611 bool aws_isalpha(uint8_t ch) {
1612 return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
1613 }
1614
aws_isdigit(uint8_t ch)1615 bool aws_isdigit(uint8_t ch) {
1616 return (ch >= '0' && ch <= '9');
1617 }
1618
aws_isxdigit(uint8_t ch)1619 bool aws_isxdigit(uint8_t ch) {
1620 return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F');
1621 }
1622
aws_isspace(uint8_t ch)1623 bool aws_isspace(uint8_t ch) {
1624 switch (ch) {
1625 case 0x20: /* ' ' - space */
1626 case 0x09: /* '\t' - horizontal tab */
1627 case 0x0A: /* '\n' - line feed */
1628 case 0x0B: /* '\v' - vertical tab */
1629 case 0x0C: /* '\f' - form feed */
1630 case 0x0D: /* '\r' - carriage return */
1631 return true;
1632 default:
1633 return false;
1634 }
1635 }
1636