LCOV - code coverage report
Current view: top level - utils - s2n_array.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 132 132 100.0 %
Date: 2025-08-15 07:28:39 Functions: 15 15 100.0 %
Branches: 85 170 50.0 %

           Branch data     Line data    Source code
       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                 :            : 
      16                 :            : #include "utils/s2n_array.h"
      17                 :            : 
      18                 :            : #include <sys/param.h>
      19                 :            : 
      20                 :            : #include "utils/s2n_blob.h"
      21                 :            : #include "utils/s2n_mem.h"
      22                 :            : #include "utils/s2n_safety.h"
      23                 :            : 
      24                 :            : S2N_RESULT s2n_array_validate(const struct s2n_array *array)
      25                 :    7890346 : {
      26                 :    7890346 :     uint32_t mem_size = 0;
      27 [ +  + ][ +  - ]:    7890346 :     RESULT_ENSURE_REF(array);
      28         [ -  + ]:    7890344 :     RESULT_GUARD(s2n_blob_validate(&array->mem));
      29 [ #  # ][ -  + ]:    7890344 :     RESULT_ENSURE_NE(array->element_size, 0);
      30         [ -  + ]:    7890344 :     RESULT_GUARD_POSIX(s2n_mul_overflow(array->len, array->element_size, &mem_size));
      31 [ -  + ][ #  # ]:    7890344 :     RESULT_ENSURE_GTE(array->mem.size, mem_size);
      32 [ #  # ][ +  - ]:    7890344 :     RESULT_ENSURE(S2N_IMPLIES(array->mem.size, array->mem.growable), S2N_ERR_SAFETY);
                 [ +  + ]
      33                 :    7890344 :     return S2N_RESULT_OK;
      34                 :    7890344 : }
      35                 :            : 
      36                 :            : static S2N_RESULT s2n_array_enlarge(struct s2n_array *array, uint32_t capacity)
      37                 :    6969672 : {
      38 [ -  + ][ #  # ]:    6969672 :     RESULT_ENSURE_REF(array);
      39                 :            : 
      40                 :            :     /* Acquire the memory */
      41                 :    6969672 :     uint32_t mem_needed = 0;
      42         [ +  + ]:    6969672 :     RESULT_GUARD_POSIX(s2n_mul_overflow(array->element_size, capacity, &mem_needed));
      43         [ -  + ]:    6969671 :     RESULT_GUARD_POSIX(s2n_realloc(&array->mem, mem_needed));
      44                 :            : 
      45                 :            :     /* Zero the extened part */
      46                 :    6969671 :     uint32_t array_elements_size = 0;
      47         [ -  + ]:    6969671 :     RESULT_GUARD_POSIX(s2n_mul_overflow(array->element_size, array->len, &array_elements_size));
      48 [ -  + ][ #  # ]:    6969671 :     RESULT_CHECKED_MEMSET(array->mem.data + array_elements_size, 0, array->mem.size - array_elements_size);
                 [ +  + ]
      49 [ -  + ][ +  - ]:    6969671 :     RESULT_POSTCONDITION(s2n_array_validate(array));
      50                 :    6969671 :     return S2N_RESULT_OK;
      51                 :    6969671 : }
      52                 :            : 
      53                 :            : struct s2n_array *s2n_array_new(uint32_t element_size)
      54                 :       1454 : {
      55                 :       1454 :     struct s2n_array *array = s2n_array_new_with_capacity(element_size, S2N_INITIAL_ARRAY_SIZE);
      56 [ +  + ][ +  - ]:       1454 :     PTR_ENSURE_REF(array);
      57                 :            : 
      58                 :       1453 :     return array;
      59                 :       1454 : }
      60                 :            : 
      61                 :            : struct s2n_array *s2n_array_new_with_capacity(uint32_t element_size, uint32_t capacity)
      62                 :       1616 : {
      63                 :       1616 :     DEFER_CLEANUP(struct s2n_blob mem = { 0 }, s2n_free);
      64         [ -  + ]:       1616 :     PTR_GUARD_POSIX(s2n_alloc(&mem, sizeof(struct s2n_array)));
      65                 :            : 
      66                 :       1616 :     DEFER_CLEANUP(struct s2n_array *array = (void *) mem.data, s2n_array_free_p);
      67                 :       1616 :     ZERO_TO_DISABLE_DEFER_CLEANUP(mem);
      68                 :            : 
      69         [ +  + ]:       1616 :     PTR_GUARD_RESULT(s2n_array_init_with_capacity(array, element_size, capacity));
      70                 :            : 
      71                 :       1615 :     struct s2n_array *array_ret = array;
      72                 :       1615 :     ZERO_TO_DISABLE_DEFER_CLEANUP(array);
      73                 :            : 
      74                 :       1615 :     return array_ret;
      75                 :       1616 : }
      76                 :            : 
      77                 :            : S2N_RESULT s2n_array_init(struct s2n_array *array, uint32_t element_size)
      78                 :    6966658 : {
      79 [ -  + ][ #  # ]:    6966658 :     RESULT_ENSURE_REF(array);
      80                 :            : 
      81         [ -  + ]:    6966658 :     RESULT_GUARD(s2n_array_init_with_capacity(array, element_size, 0));
      82                 :            : 
      83                 :    6966658 :     return S2N_RESULT_OK;
      84                 :    6966658 : }
      85                 :            : 
      86                 :            : S2N_RESULT s2n_array_init_with_capacity(struct s2n_array *array, uint32_t element_size, uint32_t capacity)
      87                 :    6968274 : {
      88 [ -  + ][ #  # ]:    6968274 :     RESULT_ENSURE_REF(array);
      89                 :            : 
      90                 :    6968274 :     *array = (struct s2n_array){ .element_size = element_size };
      91                 :            : 
      92         [ +  + ]:    6968274 :     RESULT_GUARD(s2n_array_enlarge(array, capacity));
      93                 :            : 
      94                 :    6968273 :     return S2N_RESULT_OK;
      95                 :    6968274 : }
      96                 :            : 
      97                 :            : S2N_RESULT s2n_array_pushback(struct s2n_array *array, void **element)
      98                 :       2936 : {
      99 [ +  + ][ +  + ]:       2936 :     RESULT_PRECONDITION(s2n_array_validate(array));
     100 [ -  + ][ #  # ]:       2935 :     RESULT_ENSURE_REF(element);
     101                 :       2935 :     return s2n_array_insert(array, array->len, element);
     102                 :       2935 : }
     103                 :            : 
     104                 :            : S2N_RESULT s2n_array_get(struct s2n_array *array, uint32_t idx, void **element)
     105                 :     899415 : {
     106 [ +  + ][ +  + ]:     899415 :     RESULT_PRECONDITION(s2n_array_validate(array));
     107 [ -  + ][ #  # ]:     899414 :     RESULT_ENSURE_REF(element);
     108 [ +  - ][ +  + ]:     899414 :     RESULT_ENSURE(idx < array->len, S2N_ERR_ARRAY_INDEX_OOB);
     109                 :     893150 :     *element = array->mem.data + (array->element_size * idx);
     110                 :     893150 :     return S2N_RESULT_OK;
     111                 :     899414 : }
     112                 :            : 
     113                 :            : S2N_RESULT s2n_array_insert_and_copy(struct s2n_array *array, uint32_t idx, void *element)
     114                 :       1467 : {
     115                 :       1467 :     void *insert_location = NULL;
     116         [ -  + ]:       1467 :     RESULT_GUARD(s2n_array_insert(array, idx, &insert_location));
     117 [ #  # ][ -  + ]:       1467 :     RESULT_CHECKED_MEMCPY(insert_location, element, array->element_size);
                 [ +  - ]
     118                 :       1467 :     return S2N_RESULT_OK;
     119                 :       1467 : }
     120                 :            : 
     121                 :            : S2N_RESULT s2n_array_insert(struct s2n_array *array, uint32_t idx, void **element)
     122                 :       4403 : {
     123 [ -  + ][ +  - ]:       4403 :     RESULT_PRECONDITION(s2n_array_validate(array));
     124 [ -  + ][ #  # ]:       4403 :     RESULT_ENSURE_REF(element);
     125                 :            :     /* index == len is ok since we're about to add one element */
     126 [ -  + ][ #  # ]:       4403 :     RESULT_ENSURE(idx <= array->len, S2N_ERR_ARRAY_INDEX_OOB);
     127                 :            : 
     128                 :            :     /* We are about to add one more element to the array. Add capacity if necessary */
     129                 :       4403 :     uint32_t current_capacity = 0;
     130         [ -  + ]:       4403 :     RESULT_GUARD(s2n_array_capacity(array, &current_capacity));
     131                 :            : 
     132         [ +  + ]:       4403 :     if (array->len >= current_capacity) {
     133                 :            :         /* Enlarge the array */
     134                 :       1398 :         uint32_t new_capacity = 0;
     135         [ -  + ]:       1398 :         RESULT_GUARD_POSIX(s2n_mul_overflow(current_capacity, 2, &new_capacity));
     136                 :       1398 :         new_capacity = MAX(new_capacity, S2N_INITIAL_ARRAY_SIZE);
     137         [ -  + ]:       1398 :         RESULT_GUARD(s2n_array_enlarge(array, new_capacity));
     138                 :       1398 :     }
     139                 :            : 
     140                 :            :     /* If we are adding at an existing index, slide everything down. */
     141         [ +  + ]:       4403 :     if (idx < array->len) {
     142                 :          1 :         uint32_t size = 0;
     143         [ -  + ]:          1 :         RESULT_GUARD_POSIX(s2n_mul_overflow(array->len - idx, array->element_size, &size));
     144                 :          1 :         memmove(array->mem.data + array->element_size * (idx + 1),
     145                 :          1 :                 array->mem.data + array->element_size * idx,
     146                 :          1 :                 size);
     147                 :          1 :     }
     148                 :            : 
     149                 :       4403 :     *element = array->mem.data + array->element_size * idx;
     150                 :       4403 :     array->len++;
     151                 :            : 
     152 [ -  + ][ +  - ]:       4403 :     RESULT_POSTCONDITION(s2n_array_validate(array));
     153                 :       4403 :     return S2N_RESULT_OK;
     154                 :       4403 : }
     155                 :            : 
     156                 :            : S2N_RESULT s2n_array_remove(struct s2n_array *array, uint32_t idx)
     157                 :          5 : {
     158 [ -  + ][ +  - ]:          5 :     RESULT_PRECONDITION(s2n_array_validate(array));
     159 [ -  + ][ #  # ]:          5 :     RESULT_ENSURE(idx < array->len, S2N_ERR_ARRAY_INDEX_OOB);
     160                 :            : 
     161                 :            :     /* If the removed element is the last one, no need to move anything.
     162                 :            :      * Otherwise, shift everything down */
     163         [ +  + ]:          5 :     if (idx != array->len - 1) {
     164                 :          2 :         uint32_t size = 0;
     165         [ -  + ]:          2 :         RESULT_GUARD_POSIX(s2n_mul_overflow(array->len - idx - 1, array->element_size, &size));
     166                 :          2 :         memmove(array->mem.data + array->element_size * idx,
     167                 :          2 :                 array->mem.data + array->element_size * (idx + 1),
     168                 :          2 :                 size);
     169                 :          2 :     }
     170                 :          5 :     array->len--;
     171                 :            : 
     172                 :            :     /* After shifting, zero the last element */
     173 [ #  # ][ -  + ]:          5 :     RESULT_CHECKED_MEMSET(array->mem.data + array->element_size * array->len,
                 [ +  - ]
     174                 :          5 :             0,
     175                 :          5 :             array->element_size);
     176                 :            : 
     177 [ -  + ][ +  - ]:          5 :     RESULT_POSTCONDITION(s2n_array_validate(array));
     178                 :          5 :     return S2N_RESULT_OK;
     179                 :          5 : }
     180                 :            : 
     181                 :            : S2N_RESULT s2n_array_num_elements(struct s2n_array *array, uint32_t *len)
     182                 :       4794 : {
     183 [ -  + ][ +  - ]:       4794 :     RESULT_PRECONDITION(s2n_array_validate(array));
     184 [ -  + ][ #  # ]:       4794 :     RESULT_ENSURE_MUT(len);
     185                 :            : 
     186                 :       4794 :     *len = array->len;
     187                 :            : 
     188                 :       4794 :     return S2N_RESULT_OK;
     189                 :       4794 : }
     190                 :            : 
     191                 :            : S2N_RESULT s2n_array_capacity(struct s2n_array *array, uint32_t *capacity)
     192                 :       4714 : {
     193 [ -  + ][ +  - ]:       4714 :     RESULT_PRECONDITION(s2n_array_validate(array));
     194 [ -  + ][ #  # ]:       4714 :     RESULT_ENSURE_MUT(capacity);
     195                 :            : 
     196                 :       4714 :     *capacity = array->mem.size / array->element_size;
     197                 :            : 
     198                 :       4714 :     return S2N_RESULT_OK;
     199                 :       4714 : }
     200                 :            : 
     201                 :            : S2N_CLEANUP_RESULT s2n_array_free_p(struct s2n_array **parray)
     202                 :       4698 : {
     203 [ -  + ][ #  # ]:       4698 :     RESULT_ENSURE_REF(parray);
     204                 :            : 
     205                 :       4698 :     struct s2n_array *array = *parray;
     206         [ +  + ]:       4698 :     if (array == NULL) {
     207                 :       3082 :         return S2N_RESULT_OK;
     208                 :       3082 :     }
     209                 :            : 
     210                 :            :     /* Free the elements */
     211         [ -  + ]:       1616 :     RESULT_GUARD_POSIX(s2n_free(&array->mem));
     212                 :            : 
     213                 :            :     /* And finally the array */
     214         [ -  + ]:       1616 :     RESULT_GUARD_POSIX(s2n_free_object((uint8_t **) parray, sizeof(struct s2n_array)));
     215                 :            : 
     216                 :       1616 :     return S2N_RESULT_OK;
     217                 :       1616 : }
     218                 :            : 
     219                 :            : S2N_RESULT s2n_array_free(struct s2n_array *array)
     220                 :       1470 : {
     221 [ +  - ][ +  + ]:       1470 :     RESULT_ENSURE_REF(array);
     222                 :       1469 :     return s2n_array_free_p(&array);
     223                 :       1470 : }

Generated by: LCOV version 1.14