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: 2026-07-04 07:27:58 Functions: 15 15 100.0 %
Branches: 87 172 50.6 %

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

Generated by: LCOV version 1.14