4
4
#include <sys/task.h>
5
5
#include <types.h>
6
6
7
+ #include "private/error.h"
7
8
#include "private/utils.h"
8
9
9
10
/* Memory allocator using first-fit strategy with selective coalescing.
@@ -44,15 +45,21 @@ static uint32_t free_blocks_count; /* track fragmentation */
44
45
/* Validate block integrity */
45
46
static inline bool validate_block (memblock_t * block )
46
47
{
47
- if (!IS_VALID_BLOCK (block ))
48
+ if (unlikely ( !IS_VALID_BLOCK (block ) ))
48
49
return false;
49
50
50
51
size_t size = GET_SIZE (block );
51
- if (!size || size > MALLOC_MAX_SIZE )
52
+ if (unlikely ( !size || size > MALLOC_MAX_SIZE ) )
52
53
return false;
53
54
54
55
/* Check if block extends beyond heap */
55
- if ((uint8_t * ) block + sizeof (memblock_t ) + size > (uint8_t * ) heap_end )
56
+ if (unlikely ((uint8_t * ) block + sizeof (memblock_t ) + size >
57
+ (uint8_t * ) heap_end ))
58
+ return false;
59
+
60
+ if (unlikely (block -> next &&
61
+ (uint8_t * ) block + sizeof (memblock_t ) + GET_SIZE (block ) !=
62
+ (uint8_t * ) block -> next ))
56
63
return false;
57
64
58
65
return true;
@@ -69,18 +76,17 @@ void free(void *ptr)
69
76
memblock_t * p = ((memblock_t * ) ptr ) - 1 ;
70
77
71
78
/* Validate the block being freed */
72
- if (!validate_block (p ) || !IS_USED (p )) {
79
+ if (unlikely ( !validate_block (p ) || !IS_USED (p ) )) {
73
80
CRITICAL_LEAVE ();
81
+ panic (ERR_HEAP_CORRUPT );
74
82
return ; /* Invalid or double-free */
75
83
}
76
84
77
85
MARK_FREE (p );
78
86
free_blocks_count ++ ;
79
87
80
88
/* Forward merge if the next block is free and physically adjacent */
81
- if (p -> next && !IS_USED (p -> next ) &&
82
- (uint8_t * ) p + sizeof (memblock_t ) + GET_SIZE (p ) ==
83
- (uint8_t * ) p -> next ) {
89
+ if (p -> next && !IS_USED (p -> next )) {
84
90
p -> size = GET_SIZE (p ) + sizeof (memblock_t ) + GET_SIZE (p -> next );
85
91
p -> next = p -> next -> next ;
86
92
free_blocks_count -- ;
@@ -94,9 +100,12 @@ void free(void *ptr)
94
100
current = current -> next ;
95
101
}
96
102
97
- if (prev && !IS_USED (prev ) &&
98
- (uint8_t * ) prev + sizeof (memblock_t ) + GET_SIZE (prev ) ==
99
- (uint8_t * ) p ) {
103
+ if (prev && !IS_USED (prev )) {
104
+ if (unlikely (!validate_block (prev ))) {
105
+ CRITICAL_LEAVE ();
106
+ panic (ERR_HEAP_CORRUPT );
107
+ return ;
108
+ }
100
109
prev -> size = GET_SIZE (prev ) + sizeof (memblock_t ) + GET_SIZE (p );
101
110
prev -> next = p -> next ;
102
111
free_blocks_count -- ;
@@ -109,22 +118,45 @@ void free(void *ptr)
109
118
static void selective_coalesce (void )
110
119
{
111
120
memblock_t * p = first_free ;
112
- uint32_t coalesced = 0 ;
113
121
114
122
while (p && p -> next ) {
115
123
/* Merge only when blocks are FREE *and* adjacent in memory */
116
- uint8_t * pend = (uint8_t * ) p + sizeof (memblock_t ) + GET_SIZE (p );
117
- if (!IS_USED (p ) && !IS_USED (p -> next ) && pend == (uint8_t * ) p -> next ) {
124
+ if (unlikely (!validate_block (p ))) {
125
+ panic (ERR_HEAP_CORRUPT );
126
+ return ;
127
+ }
128
+ if (!IS_USED (p ) && !IS_USED (p -> next )) {
118
129
p -> size = GET_SIZE (p ) + sizeof (memblock_t ) + GET_SIZE (p -> next );
119
130
p -> next = p -> next -> next ;
120
- coalesced ++ ;
121
131
free_blocks_count -- ;
122
132
} else {
123
133
p = p -> next ;
124
134
}
125
135
}
126
136
}
127
137
138
+ static inline void split_block (memblock_t * block , size_t size )
139
+ {
140
+ size_t remaining ;
141
+ memblock_t * new_block ;
142
+
143
+ if (unlikely (size >= GET_SIZE (block ))) {
144
+ panic (ERR_HEAP_CORRUPT );
145
+ return ;
146
+ }
147
+ remaining = GET_SIZE (block ) - size ;
148
+ /* Split only when remaining memory is large enough */
149
+ if (remaining < sizeof (memblock_t ) + MALLOC_MIN_SIZE )
150
+ return ;
151
+ new_block = (memblock_t * ) ((size_t ) block + sizeof (memblock_t ) + size );
152
+ new_block -> next = block -> next ;
153
+ new_block -> size = remaining - sizeof (memblock_t );
154
+ MARK_FREE (new_block );
155
+ block -> next = new_block ;
156
+ block -> size = size | IS_USED (block );
157
+ free_blocks_count ++ ; /* New free block created */
158
+ }
159
+
128
160
/* O(n) first-fit allocation with selective coalescing */
129
161
void * malloc (uint32_t size )
130
162
{
@@ -146,29 +178,22 @@ void *malloc(uint32_t size)
146
178
147
179
memblock_t * p = first_free ;
148
180
while (p ) {
149
- if (!validate_block (p )) {
181
+ if (unlikely ( !validate_block (p ) )) {
150
182
CRITICAL_LEAVE ();
183
+ panic (ERR_HEAP_CORRUPT );
151
184
return NULL ; /* Heap corruption detected */
152
185
}
153
186
154
187
if (!IS_USED (p ) && GET_SIZE (p ) >= size ) {
155
- size_t remaining = GET_SIZE (p ) - size ;
156
-
157
188
/* Split block only if remainder is large enough to be useful */
158
- if (remaining >= sizeof (memblock_t ) + MALLOC_MIN_SIZE ) {
159
- memblock_t * new_block =
160
- (memblock_t * ) ((size_t ) p + sizeof (memblock_t ) + size );
161
- new_block -> next = p -> next ;
162
- new_block -> size = remaining - sizeof (memblock_t );
163
- MARK_FREE (new_block );
164
- p -> next = new_block ;
165
- p -> size = size ;
166
- free_blocks_count ++ ; /* New free block created */
167
- }
189
+ split_block (p , size );
168
190
169
191
MARK_USED (p );
170
- if (free_blocks_count > 0 )
171
- free_blocks_count -- ;
192
+ if (unlikely (free_blocks_count <= 0 )) {
193
+ panic (ERR_HEAP_CORRUPT );
194
+ return NULL ;
195
+ }
196
+ free_blocks_count -- ;
172
197
173
198
CRITICAL_LEAVE ();
174
199
return (void * ) (p + 1 );
@@ -213,7 +238,7 @@ void *calloc(uint32_t nmemb, uint32_t size)
213
238
if (unlikely (nmemb && size > MALLOC_MAX_SIZE / nmemb ))
214
239
return NULL ;
215
240
216
- uint32_t total_size = nmemb * size ;
241
+ uint32_t total_size = ALIGN4 ( nmemb * size ) ;
217
242
void * buf = malloc (total_size );
218
243
219
244
if (buf )
@@ -236,11 +261,15 @@ void *realloc(void *ptr, uint32_t size)
236
261
return NULL ;
237
262
}
238
263
264
+ size = ALIGN4 (size );
265
+
239
266
memblock_t * old_block = ((memblock_t * ) ptr ) - 1 ;
240
267
241
268
/* Validate the existing block */
242
- if (!validate_block (old_block ) || !IS_USED (old_block ))
269
+ if (unlikely (!validate_block (old_block ) || !IS_USED (old_block ))) {
270
+ panic (ERR_HEAP_CORRUPT );
243
271
return NULL ;
272
+ }
244
273
245
274
size_t old_size = GET_SIZE (old_block );
246
275
@@ -249,6 +278,33 @@ void *realloc(void *ptr, uint32_t size)
249
278
old_size - size < sizeof (memblock_t ) + MALLOC_MIN_SIZE )
250
279
return ptr ;
251
280
281
+ /* fast path for shrinking */
282
+ if (size <= old_size ) {
283
+ split_block (old_block , size );
284
+ /* Trigger coalescing only when fragmentation is high */
285
+ if (free_blocks_count > COALESCE_THRESHOLD )
286
+ selective_coalesce ();
287
+ CRITICAL_LEAVE ();
288
+ return (void * ) (old_block + 1 );
289
+ }
290
+
291
+ /* fast path for growing */
292
+ if (old_block -> next && !IS_USED (old_block -> next ) &&
293
+ GET_SIZE (old_block ) + sizeof (memblock_t ) + GET_SIZE (old_block -> next ) >=
294
+ size ) {
295
+ old_block -> size = GET_SIZE (old_block ) + sizeof (memblock_t ) +
296
+ GET_SIZE (old_block -> next );
297
+ old_block -> next = old_block -> next -> next ;
298
+ free_blocks_count -- ;
299
+ split_block (old_block , size );
300
+ /* Trigger coalescing only when fragmentation is high */
301
+ if (free_blocks_count > COALESCE_THRESHOLD )
302
+ selective_coalesce ();
303
+ CRITICAL_LEAVE ();
304
+ return (void * ) (old_block + 1 );
305
+ }
306
+
307
+
252
308
void * new_buf = malloc (size );
253
309
if (new_buf ) {
254
310
memcpy (new_buf , ptr , min (old_size , size ));
0 commit comments