Branch data 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 : 4619 : static int align_to_block_boundary(
17 : : size_t requested_bytes,
18 : : size_t *aligned_bytes)
19 : : {
20 [ - + ]: 4619 : if(aligned_bytes == NULL)
21 : : {
22 : 0 : return 1;
23 : : }
24 : :
25 [ - + ]: 4619 : if(requested_bytes == 0)
26 : : {
27 : 0 : *aligned_bytes = 0;
28 : 0 : return 0;
29 : : }
30 : :
31 : 4619 : const size_t remainder = requested_bytes % MEMORY_BLOCK_BYTES;
32 : :
33 [ + + ]: 4619 : if(remainder == 0)
34 : : {
35 : 117 : *aligned_bytes = requested_bytes;
36 : 117 : return 0;
37 : : }
38 : :
39 : 4502 : const size_t padding = MEMORY_BLOCK_BYTES - remainder;
40 : :
41 [ - + ]: 4502 : if(requested_bytes > SIZE_MAX - padding)
42 : : {
43 : 0 : return 1;
44 : : }
45 : :
46 : 4502 : *aligned_bytes = requested_bytes + padding;
47 : 4502 : return 0;
48 : : }
49 : :
50 : 4650 : Return memory_resize(
51 : : memory *memory_structure,
52 : : size_t new_count,
53 : : ...)
54 : : {
55 : : /* Status returned by this function through provide()
56 : : Default value assumes successful completion */
57 : 4650 : Return status = SUCCESS;
58 : 4650 : unsigned char behavior_flags = 0U;
59 : :
60 : : va_list optional_arguments;
61 : 4650 : va_start(optional_arguments,new_count);
62 : 4650 : const unsigned int provided_flags = va_arg(optional_arguments,unsigned int);
63 : :
64 [ + + ]: 4650 : if(provided_flags == UCHAR_MAX)
65 : : {
66 : 4267 : behavior_flags = 0U;
67 : : } else {
68 : 383 : behavior_flags = (unsigned char)provided_flags;
69 : 383 : const unsigned int terminator = va_arg(optional_arguments,unsigned int);
70 : :
71 [ - + ]: 383 : if(terminator != UCHAR_MAX)
72 : : {
73 : 0 : report("Memory management; Resize flags terminator missing");
74 : 0 : status = FAILURE;
75 : : }
76 : : }
77 : 4650 : va_end(optional_arguments);
78 : :
79 : 4650 : const bool zero_new_memory = (behavior_flags & ZERO_NEW_MEMORY) != 0U;
80 : 4650 : const bool allow_shrink = (behavior_flags & RELEASE_UNUSED) != 0U;
81 : :
82 [ + - ]: 4650 : if(TRIUMPH & status)
83 : : {
84 [ + - - + ]: 4650 : if(memory_structure == NULL || memory_structure->element_size == 0)
85 : : {
86 : 0 : report("Memory management; Descriptor is NULL or not initialized");
87 : 0 : provide(FAILURE);
88 : : }
89 : : }
90 : :
91 : 4650 : size_t previous_effective_bytes = 0;
92 : 4650 : size_t previous_allocated_bytes = 0;
93 : 4650 : size_t previous_elements = 0;
94 : 4650 : size_t previous_alignment_overhead = 0;
95 : 4650 : size_t total_size_in_bytes = 0;
96 : :
97 [ + - ]: 4650 : if(TRIUMPH & status)
98 : : {
99 : 4650 : previous_elements = memory_structure->length;
100 : 4650 : previous_allocated_bytes = memory_structure->actually_allocated_bytes;
101 : 4650 : previous_effective_bytes = 0;
102 : :
103 [ + - - + ]: 4650 : run(memory_guarded_size(memory_structure->element_size,
104 : : previous_elements,
105 : : &previous_effective_bytes));
106 : :
107 [ + + ]: 4650 : if(previous_allocated_bytes > previous_effective_bytes)
108 : : {
109 : 1074 : previous_alignment_overhead = previous_allocated_bytes - previous_effective_bytes;
110 : : }
111 : : }
112 : :
113 [ + - + + ]: 4650 : if((TRIUMPH & status) && new_count == previous_elements)
114 : : {
115 [ + + ]: 31 : if(new_count == 0)
116 : : {
117 [ + - ]: 1 : if(memory_structure->data == NULL)
118 : : {
119 : 1 : telemetry_realloc_noop_counter();
120 : 1 : telemetry_noop_resize_event();
121 : 1 : provide(status);
122 : : }
123 : : } else {
124 : 30 : telemetry_realloc_noop_counter();
125 : 30 : telemetry_noop_resize_event();
126 : 30 : provide(status);
127 : : }
128 : : }
129 : :
130 : 4619 : telemetry_reset_noop_streak();
131 : :
132 [ + - - + ]: 4619 : run(memory_guarded_size(memory_structure->element_size,new_count,&total_size_in_bytes));
133 : :
134 [ - + ]: 4619 : if(CRITICAL & status)
135 : : {
136 : 0 : report("Memory management; Overflow for length=%zu (element_size=%zu)",new_count,memory_structure->element_size);
137 : : }
138 : :
139 [ + - ]: 4619 : if(TRIUMPH & status)
140 : : {
141 [ - + ]: 4619 : if(new_count == 0)
142 : : {
143 [ # # # # ]: 0 : call(del(memory_structure));
144 : : } else {
145 : 4619 : size_t aligned_size_in_bytes = 0;
146 : :
147 [ - + ]: 4619 : if(align_to_block_boundary(total_size_in_bytes,&aligned_size_in_bytes) != 0)
148 : : {
149 : 0 : report("Memory management; Allocation alignment overflow for %zu bytes",total_size_in_bytes);
150 : 0 : status = FAILURE;
151 : : } else {
152 : 4619 : const bool needs_fresh_allocation = memory_structure->data == NULL;
153 : 4619 : const bool needs_growth = aligned_size_in_bytes > memory_structure->actually_allocated_bytes;
154 [ + + ]: 4620 : const bool should_shrink = allow_shrink &&
155 [ + - ]: 1 : aligned_size_in_bytes < memory_structure->actually_allocated_bytes;
156 : :
157 [ + + + + : 4619 : if(needs_fresh_allocation || needs_growth || should_shrink)
+ + ]
158 : 3603 : {
159 : 3603 : void *resized_pointer = NULL;
160 : :
161 [ + + ]: 3603 : if(needs_fresh_allocation)
162 : : {
163 : 3574 : resized_pointer = malloc(aligned_size_in_bytes);
164 : : } else {
165 : 29 : resized_pointer = realloc(memory_structure->data,aligned_size_in_bytes);
166 : : }
167 : :
168 [ - + ]: 3603 : if(resized_pointer == NULL)
169 : : {
170 : 0 : report("Memory management; Memory allocation failed for %zu bytes",aligned_size_in_bytes);
171 : 0 : status = FAILURE;
172 : :
173 [ # # ]: 0 : if(needs_fresh_allocation)
174 : : {
175 : 0 : telemetry_allocation_failure();
176 : : } else {
177 : 0 : telemetry_reallocation_failure();
178 : : }
179 : : } else {
180 : 3603 : memory_structure->data = resized_pointer;
181 : :
182 [ + + ]: 3603 : if(needs_fresh_allocation)
183 : : {
184 : 3574 : telemetry_active_descriptor_acquire();
185 : 3574 : telemetry_new_allocations_counter();
186 : :
187 [ + - ]: 3574 : if(aligned_size_in_bytes > 0)
188 : : {
189 : 3574 : telemetry_add(aligned_size_in_bytes);
190 : : }
191 [ + + ]: 29 : } else if(needs_growth){
192 : 28 : telemetry_aligned_reallocations_counter();
193 : 28 : telemetry_add(aligned_size_in_bytes - previous_allocated_bytes);
194 [ + - ]: 1 : } else if(should_shrink){
195 : 1 : telemetry_aligned_reallocations_counter();
196 : 1 : const size_t reclaimed_bytes = previous_allocated_bytes - aligned_size_in_bytes;
197 : :
198 [ + - ]: 1 : if(reclaimed_bytes > 0)
199 : : {
200 : 1 : telemetry_release_unused_operation();
201 : 1 : telemetry_release_unused_bytes(reclaimed_bytes);
202 : 1 : telemetry_reduce(reclaimed_bytes);
203 : 1 : telemetry_free_total_bytes(reclaimed_bytes);
204 : : }
205 : : }
206 : :
207 : 3603 : memory_structure->actually_allocated_bytes = aligned_size_in_bytes;
208 : : }
209 : : } else {
210 : 1016 : telemetry_realloc_optimized_counter();
211 : : }
212 : :
213 [ + - ]: 4619 : if(TRIUMPH & status)
214 : : {
215 : 4619 : size_t bytes_to_zero = 0;
216 : :
217 [ + + + - ]: 4619 : if(zero_new_memory && total_size_in_bytes > previous_effective_bytes)
218 : : {
219 : 382 : bytes_to_zero = total_size_in_bytes - previous_effective_bytes;
220 : : }
221 : :
222 : 4619 : memory_structure->length = new_count;
223 : :
224 [ + + ]: 4619 : if(bytes_to_zero > 0)
225 : : {
226 : 382 : unsigned char *byte_view = (unsigned char *)memory_structure->data;
227 : :
228 [ - + ]: 382 : if(byte_view == NULL)
229 : : {
230 : 0 : report("Memory management; Data pointer is NULL during zero-fill");
231 : 0 : status = FAILURE;
232 : : } else {
233 : 382 : memset(byte_view + previous_effective_bytes,0,bytes_to_zero);
234 : 382 : telemetry_new_callocations_counter();
235 : : }
236 : : }
237 : :
238 [ + - ]: 4619 : if(TRIUMPH & status)
239 : : {
240 [ + + ]: 4619 : if(total_size_in_bytes > previous_effective_bytes)
241 : : {
242 : 4412 : telemetry_effective_add(total_size_in_bytes - previous_effective_bytes);
243 [ + - ]: 207 : } else if(total_size_in_bytes < previous_effective_bytes){
244 : 207 : telemetry_effective_reduce(previous_effective_bytes - total_size_in_bytes);
245 : : }
246 : : }
247 : : }
248 : : }
249 : : }
250 : : }
251 : :
252 [ + - + - ]: 4619 : if((TRIUMPH & status) && new_count != 0)
253 : : {
254 : 4619 : const size_t resulting_allocated_bytes = memory_structure->actually_allocated_bytes;
255 : 4619 : size_t new_alignment_overhead = 0;
256 : :
257 [ + + ]: 4619 : if(resulting_allocated_bytes > total_size_in_bytes)
258 : : {
259 : 4502 : new_alignment_overhead = resulting_allocated_bytes - total_size_in_bytes;
260 : : }
261 : :
262 [ + + ]: 4619 : if(new_alignment_overhead > previous_alignment_overhead)
263 : : {
264 : 3683 : telemetry_alignment_overhead_add(new_alignment_overhead - previous_alignment_overhead);
265 [ + + ]: 936 : } else if(new_alignment_overhead < previous_alignment_overhead){
266 : 817 : telemetry_alignment_overhead_reduce(previous_alignment_overhead - new_alignment_overhead);
267 : : }
268 : : }
269 : :
270 : 4619 : provide(status);
271 : : }
|