LCOV - code coverage report
Current view: top level - libs/mem/src - mem_resize.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 78.1 % 128 100
Test Date: 2026-01-12 05:34:38 Functions: 100.0 % 2 2

            Line data    Source code
       1              : #include "mem.h"
       2              : #include <stdarg.h>
       3              : #include <string.h>
       4              : #include <limits.h>
       5              : 
       6              : /**
       7              :  * @brief Round a byte size up to the allocator block boundary.
       8              :  *
       9              :  * Aligns @p requested_bytes to the next multiple of @ref MEMORY_BLOCK_BYTES, preserving zero
      10              :  * and guarding against overflow. Returns non-zero on error so callers can log and fail early.
      11              :  *
      12              :  * @param requested_bytes Number of bytes requested by the caller.
      13              :  * @param aligned_bytes   Output pointer receiving the aligned size when successful.
      14              :  * @return 0 on success; non-zero if @p aligned_bytes is NULL or an overflow occurred.
      15              :  */
      16         2042 : static int align_to_block_boundary(
      17              :         size_t requested_bytes,
      18              :         size_t *aligned_bytes)
      19              : {
      20         2042 :         if(aligned_bytes == NULL)
      21              :         {
      22            0 :                 return 1;
      23              :         }
      24              : 
      25         2042 :         if(requested_bytes == 0)
      26              :         {
      27            0 :                 *aligned_bytes = 0;
      28            0 :                 return 0;
      29              :         }
      30              : 
      31         2042 :         const size_t remainder = requested_bytes % MEMORY_BLOCK_BYTES;
      32              : 
      33         2042 :         if(remainder == 0)
      34              :         {
      35           78 :                 *aligned_bytes = requested_bytes;
      36           78 :                 return 0;
      37              :         }
      38              : 
      39         1964 :         const size_t padding = MEMORY_BLOCK_BYTES - remainder;
      40              : 
      41         1964 :         if(requested_bytes > SIZE_MAX - padding)
      42              :         {
      43            0 :                 return 1;
      44              :         }
      45              : 
      46         1964 :         *aligned_bytes = requested_bytes + padding;
      47         1964 :         return 0;
      48              : }
      49              : 
      50         2069 : Return memory_resize(
      51              :         memory *memory_structure,
      52              :         size_t new_count,
      53              :         ...)
      54              : {
      55              :         /** Return status
      56              :          *  The status that will be passed to return() before exiting
      57              :          *  By default, the function worked without errors
      58              :          */
      59         2069 :         Return status = SUCCESS;
      60         2069 :         unsigned char behavior_flags = 0U;
      61              : 
      62              :         va_list optional_arguments;
      63         2069 :         va_start(optional_arguments,new_count);
      64         2069 :         const unsigned int provided_flags = va_arg(optional_arguments,unsigned int);
      65              : 
      66         2069 :         if(provided_flags == UCHAR_MAX)
      67              :         {
      68         2068 :                 behavior_flags = 0U;
      69              :         } else {
      70            1 :                 behavior_flags = (unsigned char)provided_flags;
      71            1 :                 const unsigned int terminator = va_arg(optional_arguments,unsigned int);
      72              : 
      73            1 :                 if(terminator != UCHAR_MAX)
      74              :                 {
      75            0 :                         slog(ERROR,"Memory management; Resize flags terminator missing");
      76            0 :                         status = FAILURE;
      77              :                 }
      78              :         }
      79         2069 :         va_end(optional_arguments);
      80              : 
      81         2069 :         const bool zero_new_memory = (behavior_flags & ZERO_NEW_MEMORY) != 0U;
      82         2069 :         const bool allow_shrink = (behavior_flags & RELEASE_UNUSED) != 0U;
      83              : 
      84         2069 :         if(SUCCESS == status)
      85              :         {
      86         2069 :                 if(memory_structure == NULL || memory_structure->element_size == 0)
      87              :                 {
      88            0 :                         slog(ERROR,"Memory management; Descriptor is NULL or not initialized");
      89            0 :                         provide(FAILURE);
      90              :                 }
      91              :         }
      92              : 
      93         2069 :         size_t previous_effective_bytes = 0;
      94         2069 :         size_t previous_allocated_bytes = 0;
      95         2069 :         size_t previous_elements = 0;
      96         2069 :         size_t previous_alignment_overhead = 0;
      97         2069 :         size_t total_size_in_bytes = 0;
      98              : 
      99         2069 :         if(SUCCESS == status)
     100              :         {
     101         2069 :                 previous_elements = memory_structure->length;
     102         2069 :                 previous_allocated_bytes = memory_structure->actually_allocated_bytes;
     103         2069 :                 previous_effective_bytes = 0;
     104              : 
     105         2069 :                 run(memory_guarded_size(memory_structure->element_size,
     106              :                         previous_elements,
     107              :                         &previous_effective_bytes));
     108              : 
     109         2069 :                 if(previous_allocated_bytes > previous_effective_bytes)
     110              :                 {
     111          799 :                         previous_alignment_overhead = previous_allocated_bytes - previous_effective_bytes;
     112              :                 }
     113              :         }
     114              : 
     115         2069 :         if(SUCCESS == status && new_count == previous_elements)
     116              :         {
     117           27 :                 if(new_count == 0)
     118              :                 {
     119            1 :                         if(memory_structure->data == NULL)
     120              :                         {
     121            1 :                                 telemetry_realloc_noop_counter();
     122            1 :                                 telemetry_noop_resize_event();
     123            1 :                                 provide(status);
     124              :                         }
     125              :                 } else {
     126           26 :                         telemetry_realloc_noop_counter();
     127           26 :                         telemetry_noop_resize_event();
     128           26 :                         provide(status);
     129              :                 }
     130              :         }
     131              : 
     132         2042 :         telemetry_reset_noop_streak();
     133              : 
     134         2042 :         run(memory_guarded_size(memory_structure->element_size,new_count,&total_size_in_bytes));
     135              : 
     136         2042 :         if(FAILURE == status)
     137              :         {
     138            0 :                 slog(ERROR,
     139              :                         "Memory management; Overflow for length=%zu (element_size=%zu)",
     140              :                         new_count,
     141              :                         memory_structure->element_size);
     142              :         }
     143              : 
     144         2042 :         if(SUCCESS == status)
     145              :         {
     146         2042 :                 if(new_count == 0)
     147              :                 {
     148            0 :                         run(del(memory_structure));
     149              :                 } else {
     150         2042 :                         size_t aligned_size_in_bytes = 0;
     151              : 
     152         2042 :                         if(align_to_block_boundary(total_size_in_bytes,&aligned_size_in_bytes) != 0)
     153              :                         {
     154            0 :                                 slog(ERROR,
     155              :                                         "Memory management; Allocation alignment overflow for %zu bytes",
     156              :                                         total_size_in_bytes);
     157            0 :                                 status = FAILURE;
     158              :                         } else {
     159         2042 :                                 const bool needs_fresh_allocation = memory_structure->data == NULL;
     160         2042 :                                 const bool needs_growth = aligned_size_in_bytes > memory_structure->actually_allocated_bytes;
     161         2042 :                                 const bool should_shrink = allow_shrink &&
     162            0 :                                         aligned_size_in_bytes < memory_structure->actually_allocated_bytes;
     163              : 
     164         2042 :                                 if(needs_fresh_allocation || needs_growth || should_shrink)
     165         1294 :                                 {
     166         1294 :                                         void *resized_pointer = NULL;
     167              : 
     168         1294 :                                         if(needs_fresh_allocation)
     169              :                                         {
     170         1268 :                                                 resized_pointer = malloc(aligned_size_in_bytes);
     171              :                                         } else {
     172           26 :                                                 resized_pointer = realloc(memory_structure->data,aligned_size_in_bytes);
     173              :                                         }
     174              : 
     175         1294 :                                         if(resized_pointer == NULL)
     176              :                                         {
     177            0 :                                                 slog(ERROR,
     178              :                                                         "Memory management; Memory allocation failed for %zu bytes",
     179              :                                                         aligned_size_in_bytes);
     180            0 :                                                 status = FAILURE;
     181              : 
     182            0 :                                                 if(needs_fresh_allocation)
     183              :                                                 {
     184            0 :                                                         telemetry_allocation_failure();
     185              :                                                 } else {
     186            0 :                                                         telemetry_reallocation_failure();
     187              :                                                 }
     188              :                                         } else {
     189         1294 :                                                 memory_structure->data = resized_pointer;
     190              : 
     191         1294 :                                                 if(needs_fresh_allocation)
     192              :                                                 {
     193         1268 :                                                         telemetry_active_descriptor_acquire();
     194         1268 :                                                         telemetry_new_allocations_counter();
     195              : 
     196         1268 :                                                         if(aligned_size_in_bytes > 0)
     197              :                                                         {
     198         1268 :                                                                 telemetry_add(aligned_size_in_bytes);
     199              :                                                         }
     200           26 :                                                 } else if(needs_growth){
     201           26 :                                                         telemetry_aligned_reallocations_counter();
     202           26 :                                                         telemetry_add(aligned_size_in_bytes - previous_allocated_bytes);
     203            0 :                                                 } else if(should_shrink){
     204            0 :                                                         telemetry_aligned_reallocations_counter();
     205            0 :                                                         const size_t reclaimed_bytes = previous_allocated_bytes - aligned_size_in_bytes;
     206              : 
     207            0 :                                                         if(reclaimed_bytes > 0)
     208              :                                                         {
     209            0 :                                                                 telemetry_release_unused_operation();
     210            0 :                                                                 telemetry_release_unused_bytes(reclaimed_bytes);
     211            0 :                                                                 telemetry_reduce(reclaimed_bytes);
     212            0 :                                                                 telemetry_free_total_bytes(reclaimed_bytes);
     213              :                                                         }
     214              :                                                 }
     215              : 
     216         1294 :                                                 memory_structure->actually_allocated_bytes = aligned_size_in_bytes;
     217              :                                         }
     218              :                                 } else {
     219          748 :                                         telemetry_realloc_optimized_counter();
     220              :                                 }
     221              : 
     222         2042 :                                 if(SUCCESS == status)
     223              :                                 {
     224         2042 :                                         size_t bytes_to_zero = 0;
     225              : 
     226         2042 :                                         if(zero_new_memory && total_size_in_bytes > previous_effective_bytes)
     227              :                                         {
     228            1 :                                                 bytes_to_zero = total_size_in_bytes - previous_effective_bytes;
     229              :                                         }
     230              : 
     231         2042 :                                         memory_structure->length = new_count;
     232              : 
     233         2042 :                                         if(bytes_to_zero > 0)
     234              :                                         {
     235            1 :                                                 unsigned char *byte_view = (unsigned char *)memory_structure->data;
     236              : 
     237            1 :                                                 if(byte_view == NULL)
     238              :                                                 {
     239            0 :                                                         slog(ERROR,"Memory management; Data pointer is NULL during zero-fill");
     240            0 :                                                         status = FAILURE;
     241              :                                                 } else {
     242            1 :                                                         memset(byte_view + previous_effective_bytes,0,bytes_to_zero);
     243            1 :                                                         telemetry_new_callocations_counter();
     244              :                                                 }
     245              :                                         }
     246              : 
     247         2042 :                                         if(SUCCESS == status)
     248              :                                         {
     249         2042 :                                                 if(total_size_in_bytes > previous_effective_bytes)
     250              :                                                 {
     251         1828 :                                                         telemetry_effective_add(total_size_in_bytes - previous_effective_bytes);
     252          214 :                                                 } else if(total_size_in_bytes < previous_effective_bytes){
     253          214 :                                                         telemetry_effective_reduce(previous_effective_bytes - total_size_in_bytes);
     254              :                                                 }
     255              :                                         }
     256              :                                 }
     257              :                         }
     258              :                 }
     259              :         }
     260              : 
     261         2042 :         if(SUCCESS == status && new_count != 0)
     262              :         {
     263         2042 :                 const size_t resulting_allocated_bytes = memory_structure->actually_allocated_bytes;
     264         2042 :                 size_t new_alignment_overhead = 0;
     265              : 
     266         2042 :                 if(resulting_allocated_bytes > total_size_in_bytes)
     267              :                 {
     268         1964 :                         new_alignment_overhead = resulting_allocated_bytes - total_size_in_bytes;
     269              :                 }
     270              : 
     271         2042 :                 if(new_alignment_overhead > previous_alignment_overhead)
     272              :                 {
     273         1425 :                         telemetry_alignment_overhead_add(new_alignment_overhead - previous_alignment_overhead);
     274          617 :                 } else if(new_alignment_overhead < previous_alignment_overhead){
     275          539 :                         telemetry_alignment_overhead_reduce(previous_alignment_overhead - new_alignment_overhead);
     276              :                 }
     277              :         }
     278              : 
     279         2042 :         provide(status);
     280              : }
        

Generated by: LCOV version 2.0-1