s2n_array.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /*
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License").
  5. * You may not use this file except in compliance with the License.
  6. * A copy of the License is located at
  7. *
  8. * http://aws.amazon.com/apache2.0
  9. *
  10. * or in the "license" file accompanying this file. This file is distributed
  11. * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  12. * express or implied. See the License for the specific language governing
  13. * permissions and limitations under the License.
  14. */
  15. #include "utils/s2n_array.h"
  16. #include <sys/param.h>
  17. #include "utils/s2n_blob.h"
  18. #include "utils/s2n_mem.h"
  19. #include "utils/s2n_safety.h"
  20. S2N_RESULT s2n_array_validate(const struct s2n_array *array)
  21. {
  22. uint32_t mem_size = 0;
  23. RESULT_ENSURE_REF(array);
  24. RESULT_GUARD(s2n_blob_validate(&array->mem));
  25. RESULT_ENSURE_NE(array->element_size, 0);
  26. RESULT_GUARD_POSIX(s2n_mul_overflow(array->len, array->element_size, &mem_size));
  27. RESULT_ENSURE_GTE(array->mem.size, mem_size);
  28. RESULT_ENSURE(S2N_IMPLIES(array->mem.size, array->mem.growable), S2N_ERR_SAFETY);
  29. return S2N_RESULT_OK;
  30. }
  31. static S2N_RESULT s2n_array_enlarge(struct s2n_array *array, uint32_t capacity)
  32. {
  33. RESULT_ENSURE_REF(array);
  34. /* Acquire the memory */
  35. uint32_t mem_needed;
  36. RESULT_GUARD_POSIX(s2n_mul_overflow(array->element_size, capacity, &mem_needed));
  37. RESULT_GUARD_POSIX(s2n_realloc(&array->mem, mem_needed));
  38. /* Zero the extened part */
  39. uint32_t array_elements_size;
  40. RESULT_GUARD_POSIX(s2n_mul_overflow(array->element_size, array->len, &array_elements_size));
  41. RESULT_CHECKED_MEMSET(array->mem.data + array_elements_size, 0, array->mem.size - array_elements_size);
  42. RESULT_POSTCONDITION(s2n_array_validate(array));
  43. return S2N_RESULT_OK;
  44. }
  45. struct s2n_array *s2n_array_new(uint32_t element_size)
  46. {
  47. struct s2n_array *array = s2n_array_new_with_capacity(element_size, S2N_INITIAL_ARRAY_SIZE);
  48. PTR_ENSURE_REF(array);
  49. return array;
  50. }
  51. struct s2n_array *s2n_array_new_with_capacity(uint32_t element_size, uint32_t capacity)
  52. {
  53. DEFER_CLEANUP(struct s2n_blob mem = { 0 }, s2n_free);
  54. PTR_GUARD_POSIX(s2n_alloc(&mem, sizeof(struct s2n_array)));
  55. DEFER_CLEANUP(struct s2n_array *array = (void *) mem.data, s2n_array_free_p);
  56. ZERO_TO_DISABLE_DEFER_CLEANUP(mem);
  57. PTR_GUARD_RESULT(s2n_array_init_with_capacity(array, element_size, capacity));
  58. struct s2n_array *array_ret = array;
  59. ZERO_TO_DISABLE_DEFER_CLEANUP(array);
  60. return array_ret;
  61. }
  62. S2N_RESULT s2n_array_init(struct s2n_array *array, uint32_t element_size)
  63. {
  64. RESULT_ENSURE_REF(array);
  65. RESULT_GUARD(s2n_array_init_with_capacity(array, element_size, 0));
  66. return S2N_RESULT_OK;
  67. }
  68. S2N_RESULT s2n_array_init_with_capacity(struct s2n_array *array, uint32_t element_size, uint32_t capacity)
  69. {
  70. RESULT_ENSURE_REF(array);
  71. *array = (struct s2n_array){ .element_size = element_size };
  72. RESULT_GUARD(s2n_array_enlarge(array, capacity));
  73. return S2N_RESULT_OK;
  74. }
  75. S2N_RESULT s2n_array_pushback(struct s2n_array *array, void **element)
  76. {
  77. RESULT_PRECONDITION(s2n_array_validate(array));
  78. RESULT_ENSURE_REF(element);
  79. return s2n_array_insert(array, array->len, element);
  80. }
  81. S2N_RESULT s2n_array_get(struct s2n_array *array, uint32_t idx, void **element)
  82. {
  83. RESULT_PRECONDITION(s2n_array_validate(array));
  84. RESULT_ENSURE_REF(element);
  85. RESULT_ENSURE(idx < array->len, S2N_ERR_ARRAY_INDEX_OOB);
  86. *element = array->mem.data + (array->element_size * idx);
  87. return S2N_RESULT_OK;
  88. }
  89. S2N_RESULT s2n_array_insert_and_copy(struct s2n_array *array, uint32_t idx, void *element)
  90. {
  91. void *insert_location = NULL;
  92. RESULT_GUARD(s2n_array_insert(array, idx, &insert_location));
  93. RESULT_CHECKED_MEMCPY(insert_location, element, array->element_size);
  94. return S2N_RESULT_OK;
  95. }
  96. S2N_RESULT s2n_array_insert(struct s2n_array *array, uint32_t idx, void **element)
  97. {
  98. RESULT_PRECONDITION(s2n_array_validate(array));
  99. RESULT_ENSURE_REF(element);
  100. /* index == len is ok since we're about to add one element */
  101. RESULT_ENSURE(idx <= array->len, S2N_ERR_ARRAY_INDEX_OOB);
  102. /* We are about to add one more element to the array. Add capacity if necessary */
  103. uint32_t current_capacity = 0;
  104. RESULT_GUARD(s2n_array_capacity(array, &current_capacity));
  105. if (array->len >= current_capacity) {
  106. /* Enlarge the array */
  107. uint32_t new_capacity = 0;
  108. RESULT_GUARD_POSIX(s2n_mul_overflow(current_capacity, 2, &new_capacity));
  109. new_capacity = MAX(new_capacity, S2N_INITIAL_ARRAY_SIZE);
  110. RESULT_GUARD(s2n_array_enlarge(array, new_capacity));
  111. }
  112. /* If we are adding at an existing index, slide everything down. */
  113. if (idx < array->len) {
  114. uint32_t size = 0;
  115. RESULT_GUARD_POSIX(s2n_mul_overflow(array->len - idx, array->element_size, &size));
  116. memmove(array->mem.data + array->element_size * (idx + 1),
  117. array->mem.data + array->element_size * idx,
  118. size);
  119. }
  120. *element = array->mem.data + array->element_size * idx;
  121. array->len++;
  122. RESULT_POSTCONDITION(s2n_array_validate(array));
  123. return S2N_RESULT_OK;
  124. }
  125. S2N_RESULT s2n_array_remove(struct s2n_array *array, uint32_t idx)
  126. {
  127. RESULT_PRECONDITION(s2n_array_validate(array));
  128. RESULT_ENSURE(idx < array->len, S2N_ERR_ARRAY_INDEX_OOB);
  129. /* If the removed element is the last one, no need to move anything.
  130. * Otherwise, shift everything down */
  131. if (idx != array->len - 1) {
  132. uint32_t size = 0;
  133. RESULT_GUARD_POSIX(s2n_mul_overflow(array->len - idx - 1, array->element_size, &size));
  134. memmove(array->mem.data + array->element_size * idx,
  135. array->mem.data + array->element_size * (idx + 1),
  136. size);
  137. }
  138. array->len--;
  139. /* After shifting, zero the last element */
  140. RESULT_CHECKED_MEMSET(array->mem.data + array->element_size * array->len,
  141. 0,
  142. array->element_size);
  143. RESULT_POSTCONDITION(s2n_array_validate(array));
  144. return S2N_RESULT_OK;
  145. }
  146. S2N_RESULT s2n_array_num_elements(struct s2n_array *array, uint32_t *len)
  147. {
  148. RESULT_PRECONDITION(s2n_array_validate(array));
  149. RESULT_ENSURE_MUT(len);
  150. *len = array->len;
  151. return S2N_RESULT_OK;
  152. }
  153. S2N_RESULT s2n_array_capacity(struct s2n_array *array, uint32_t *capacity)
  154. {
  155. RESULT_PRECONDITION(s2n_array_validate(array));
  156. RESULT_ENSURE_MUT(capacity);
  157. *capacity = array->mem.size / array->element_size;
  158. return S2N_RESULT_OK;
  159. }
  160. S2N_CLEANUP_RESULT s2n_array_free_p(struct s2n_array **parray)
  161. {
  162. RESULT_ENSURE_REF(parray);
  163. struct s2n_array *array = *parray;
  164. if (array == NULL) {
  165. return S2N_RESULT_OK;
  166. }
  167. /* Free the elements */
  168. RESULT_GUARD_POSIX(s2n_free(&array->mem));
  169. /* And finally the array */
  170. RESULT_GUARD_POSIX(s2n_free_object((uint8_t **) parray, sizeof(struct s2n_array)));
  171. return S2N_RESULT_OK;
  172. }
  173. S2N_RESULT s2n_array_free(struct s2n_array *array)
  174. {
  175. RESULT_ENSURE_REF(array);
  176. return s2n_array_free_p(&array);
  177. }