LAMMP 4.1.0
Lamina High-Precision Arithmetic Library
载入中...
搜索中...
未找到
memory.c
浏览该文件的文档.
1/*
2 * LAMMP - Copyright (C) 2025-2026 HJimmyK(Jericho Knox)
3 * This file is part of lammp, under the GNU LGPL v2 license.
4 * See LICENSE in the project root for the full license text.
5 */
6
7#include "../../include/lammp/impl/mparam.h"
8#include "../../include/lammp/impl/prime_table.h"
9#include "../../include/lammp/impl/tmp_alloc.h"
10#include "../../include/lammp/lmmpn.h"
11
12#undef lmmp_alloc
13#undef lmmp_realloc
14#undef lmmp_free
15#undef lmmp_stack_alloc
16#undef lmmp_stack_free
17#undef lmmp_leak_tracker
18#define HSIZE sizeof(void*)
19
21 malloc,
22 free,
23 realloc,
24};
25
26#define heap_alloc_func global_heap.alloc
27#define heap_free_func global_heap.free
28#define realloc_func global_heap.realloc
29
31
35
36#define stack_get_top_func() (lmmp_stack_top)
37#define stack_set_top_func(top) (lmmp_stack_top = top)
38
39void lmmp_stack_reset(size_t size) {
40 if (size) {
44 }
45 if (lmmp_stack_begin == NULL) {
46 lmmp_abort(LAMMP_ERROR_MEMORY_ALLOC_FAILURE, "Default stack allocation failed", __func__, __LINE__);
47 }
49 } else {
50#if LAMMP_DEBUG_MEMORY_LEAK == 1
52 char msg[128];
53 snprintf(msg, sizeof(msg), "Default stack allocator is not empty. top: %p, begin: %p, end: %p\n",
55 lmmp_abort(LAMMP_ERROR_MEMORY_LEAK, msg, __func__, __LINE__);
56 }
57#endif
60 lmmp_stack_begin = NULL;
61 lmmp_stack_end = NULL;
62 lmmp_stack_top = NULL;
63 }
64}
65
75
77 if (heap == NULL)
78 return;
80#if LAMMP_DEBUG_MEMORY_LEAK == 1
81 if (heap_alloc_count != 0) {
82 char msg[64];
83 snprintf(msg, sizeof(msg), "Older heap allocations not freed: %d block(s)", heap_alloc_count);
84 lmmp_abort(LAMMP_ERROR_MEMORY_LEAK, msg, __func__, __LINE__);
85 }
86#endif
87 global_heap = *heap;
89}
90
91void* lmmp_temp_heap_alloc_(void** pmarker, size_t size) {
92 /*
93 * pmarker is a head pointer to a linked list of allocated memory blocks.
94 * Each allocated block has a header of size HSIZE, which is used to store the
95 * next pointer of the block. The actual data starts at (mp_byte_t*)p + offset.
96 */
97 const size_t offset = LMMP_ROUND_UP_MULTIPLE(HSIZE, LAMMP_MAX_ALIGN);
98 void* p = heap_alloc_func(size + offset);
99 *(void**)p = *pmarker;
100 *pmarker = p;
101 return (mp_byte_t*)p + offset;
102}
103
104void lmmp_temp_heap_free_(void* marker) {
105 /*
106 * Free all allocated memory blocks in the linked list pointed to by pmarker.
107 */
108 while (marker) {
109 void* next = *(void**)marker;
110 heap_free_func(marker);
111 marker = next;
112 }
113}
114
115#include "../../include/lammp/impl/safe_memory.h"
116
117static inline void lmmp_chech_memory(size_t size, const char* func, int line) {
118 char msg[64];
119 snprintf(msg, sizeof(msg), "Memory allocation failed (size: %zu bytes)", size);
121}
122
123int lmmp_alloc_count(int cnt) {
124 if (cnt != 0) {
125 int new_cnt = cnt;
126 cnt = heap_alloc_count;
127 heap_alloc_count = new_cnt;
128 return cnt;
129 }
130 return heap_alloc_count;
131}
132
133void lmmp_leak_tracker(const char* func, int line) {
134 char msg[192] = {0};
135 int offset = 0;
136 const int max_len = sizeof(msg) - 1;
137 int t = 0;
138 if (heap_alloc_count != 0) {
139 offset +=
140 snprintf(msg + offset, max_len - offset, "Heap allocations not freed: %d block(s)\n", heap_alloc_count);
141 t = 1;
142 }
144 offset += snprintf(msg + offset, max_len - offset,
145 "Default stack allocator is not empty. top: %p, begin: %p, end: %p\n",
147 t = 1;
148 }
149 if (t) {
150 lmmp_abort(LAMMP_ERROR_MEMORY_LEAK, msg, func, line);
151 }
152}
153
154#if LAMMP_DEBUG_MEMORY_CHECK == 1
155void* lmmp_alloc(size_t size, const char* func, int line) {
156 if (size) {
157 void* ret = lmmp_alloc_debug(size, func, line);
158#if LAMMP_DEBUG_MEMORY_LEAK == 1
160#endif
161 return ret;
162 }
163 return NULL;
164}
165#else
166void* lmmp_alloc(size_t size) {
167 if (size) {
168 void* ret = heap_alloc_func(size);
169 if (ret == NULL)
170 lmmp_chech_memory(size, __func__, __LINE__);
171#if LAMMP_DEBUG_MEMORY_LEAK == 1
173#endif
174 return ret;
175 }
176 return NULL;
177}
178#endif
179
180#if LAMMP_DEBUG_MEMORY_CHECK == 1
181void* lmmp_realloc(void* oldptr, size_t new_size, const char* func, int line) {
182 void* ret = lmmp_realloc_debug(oldptr, new_size, func, line);
183 return ret;
184}
185#else
186void* lmmp_realloc(void* oldptr, size_t new_size) {
187 void* ret = realloc_func(oldptr, new_size);
188 if (ret == NULL)
189 lmmp_chech_memory(new_size, __func__, __LINE__);
190 return ret;
191}
192#endif
193
194#if LAMMP_DEBUG_MEMORY_CHECK == 1
195void lmmp_free(void* ptr, const char* func, int line) {
196 if (ptr) {
197 lmmp_free_debug(ptr, func, line);
198#if LAMMP_DEBUG_MEMORY_LEAK == 1
200#endif
201 }
202}
203#else
204void lmmp_free(void* ptr) {
205 if (ptr) {
206 heap_free_func(ptr);
207#if LAMMP_DEBUG_MEMORY_LEAK == 1
209#endif
210 }
211}
212#endif
213
214#if LAMMP_DEBUG_MEMORY_CHECK != 1
215
216#define SIZE_SIZE LMMP_ROUND_UP_MULTIPLE(sizeof(size_t), LAMMP_MAX_ALIGN)
217
218void* lmmp_stack_alloc(size_t size) {
219 if (size == 0) {
220 return NULL;
221 }
222 size_t total_size = SIZE_SIZE + LMMP_ROUND_UP_MULTIPLE(size, LAMMP_MAX_ALIGN);
223 void* old_top = stack_get_top_func();
224 void* new_top = (mp_byte_t*)old_top + total_size;
225#if LAMMP_DEBUG_STACK_OVERFLOW_CHECK == 1
226 if (new_top > lmmp_stack_end) {
227 char msg[128];
228 snprintf(msg, sizeof(msg), "Stack overflow (trying to allocate: %zu bytes, stack remaining: %zu bytes)",
229 total_size, (size_t)((mp_byte_t*)lmmp_stack_end - (mp_byte_t*)old_top));
230 lmmp_abort(LAMMP_ERROR_MEMORY_ALLOC_FAILURE, msg, __func__, __LINE__);
231 }
232#endif // LAMMP_DEBUG_STACK_OVERFLOW_CHECK == 1
233 stack_set_top_func(new_top);
234 *(size_t*)old_top = total_size;
235 return (mp_byte_t*)old_top + SIZE_SIZE;
236}
237
238void lmmp_stack_free(void* ptr) {
239 if (ptr == NULL) {
240 return;
241 }
242#if LAMMP_DEBUG_STACK_OVERFLOW_CHECK == 1
243 if (ptr < lmmp_stack_begin || ptr >= lmmp_stack_end) {
244 char msg[128];
245 snprintf(msg, sizeof(msg), "Invalid stack pointer (trying to free: %p ; stack start: %p , stack end: %p )", ptr,
247 lmmp_abort(LAMMP_ERROR_MEMORY_FREE_FAILURE, msg, __func__, __LINE__);
248 }
249#endif // LAMMP_DEBUG_STACK_OVERFLOW_CHECK == 1
250 void* old_top = stack_get_top_func();
251 size_t total_size = *(size_t*)((mp_byte_t*)ptr - SIZE_SIZE);
252 void* new_top = (mp_byte_t*)old_top - total_size;
253#if LAMMP_DEBUG_STACK_OVERFLOW_CHECK == 1
254 if (new_top < lmmp_stack_begin || new_top > lmmp_stack_end) {
255 char msg[256];
256 snprintf(msg, sizeof(msg),
257 "Stack underflow (trying to free: %p , size: %zu bytes ; stack start: %p , stack end: %p ) \n%s", ptr,
259 "Likely cause: Previous stack buffer overflow corrupted the memory header.");
260 lmmp_abort(LAMMP_ERROR_MEMORY_FREE_FAILURE, msg, __func__, __LINE__);
261 }
262#endif // LAMMP_DEBUG_STACK_OVERFLOW_CHECK == 1
263 stack_set_top_func(new_top);
264}
265
266#else
267
268typedef struct {
269 size_t total_size; // 总分配大小(原有)
270 size_t extra_size; // 额外分配的魔数区域大小
271 size_t magic_addr_offset; // 魔数起始地址相对于old_top的偏移
272 void* last_ptr; // 上一次分配的指针
273 const char* func; // 分配时的函数名
274 int line; // 分配时的文件行号
275} StackHeader;
276
277#define HEADER_SIZE sizeof(StackHeader)
278
279#define MAGIC_NUMBER 0xDEADBEEF
280#define MAGIC_SIZE sizeof(unsigned int)
281
282static LAMMP_THREAD_LOCAL void* global_stack_last_ptr = NULL; // 最后一次分配的指针
283
284void* lmmp_stack_alloc(size_t size, const char* func, int line) {
285 if (size == 0) {
286 return NULL;
287 }
288
289 size_t base_data_size = LMMP_ROUND_UP_MULTIPLE(size, LAMMP_MAX_ALIGN);
290 size_t base_total_size = HEADER_SIZE + base_data_size;
291
292 size_t extra_size = (base_total_size * LAMMP_MEMORY_MORE_ALLOC_TIMES) / 10;
293 if (extra_size < MAGIC_SIZE) {
294 extra_size = MAGIC_SIZE;
295 }
296 size_t total_size = base_total_size + extra_size;
297
298 void* old_top = stack_get_top_func();
299 void* new_top = (mp_byte_t*)old_top + total_size;
300 if (new_top > lmmp_stack_end) {
301 char msg[128];
302 snprintf(msg, sizeof(msg), "Stack overflow (alloc: %zu bytes, remaining: %zu bytes)", total_size,
303 (size_t)((mp_byte_t*)lmmp_stack_end - (mp_byte_t*)old_top));
305 }
306
307 StackHeader* header = (StackHeader*)old_top;
308 header->total_size = total_size;
309 header->extra_size = extra_size;
310 header->magic_addr_offset = base_total_size; // 魔数起始地址 = old_top + base_total_size
311 header->last_ptr = global_stack_last_ptr;
312 header->func = func;
313 header->line = line;
314 void* magic_addr = (mp_byte_t*)old_top + header->magic_addr_offset;
315 memset(magic_addr, 0, extra_size);
316 for (size_t i = 0; i + MAGIC_SIZE <= extra_size; i += MAGIC_SIZE) {
317 *(unsigned int*)((mp_byte_t*)magic_addr + i) = MAGIC_NUMBER;
318 }
319
320 stack_set_top_func(new_top);
321 void* alloc_ptr = (mp_byte_t*)old_top + HEADER_SIZE;
322
323 global_stack_last_ptr = alloc_ptr;
324
325 return alloc_ptr;
326}
327
328void lmmp_stack_free(void* ptr, const char* func, int line) {
329 if (ptr == NULL) {
330 return;
331 }
332 if (ptr < lmmp_stack_begin || ptr >= lmmp_stack_end) {
333 char msg[128];
334 snprintf(msg, sizeof(msg), "Invalid stack pointer, trying to free %p (stack start: %p, end: %p)", ptr,
337 }
338 if (ptr != global_stack_last_ptr) {
339 char msg[96];
340 snprintf(msg, sizeof(msg), "Invalid stack pointer. Expected %p, but try to free %p", global_stack_last_ptr,
341 ptr);
343 }
344
345 StackHeader* header = (StackHeader*)((mp_byte_t*)ptr - HEADER_SIZE);
346 size_t total_size = header->total_size;
347 size_t extra_size = header->extra_size;
348 void* magic_addr = (mp_byte_t*)header + header->magic_addr_offset;
349 global_stack_last_ptr = header->last_ptr;
350 int magic_corrupted = 0;
351 for (size_t i = 0; i + MAGIC_SIZE <= extra_size; i += MAGIC_SIZE) {
352 unsigned int magic = *(unsigned int*)((mp_byte_t*)magic_addr + i);
353 if (magic != MAGIC_NUMBER) {
354 magic_corrupted = 1;
355 break;
356 }
357 }
358 if (magic_corrupted) {
359 char error_buf[512];
360 int offset = 0;
361 const int buf_size = sizeof(error_buf);
362
363#define SAFE_APPEND(...) \
364 do { \
365 if (offset < buf_size) { \
366 int n = snprintf(error_buf + offset, (size_t)(buf_size - offset), __VA_ARGS__); \
367 if (n > 0) \
368 offset += n; \
369 } \
370 } while (0)
371
372 SAFE_APPEND("Stack buffer overflow detected! Magic number corrupted at %p (ptr: %p, size: %zu)\n", magic_addr,
373 ptr, (mp_byte_t*)magic_addr - (mp_byte_t*)ptr);
374 SAFE_APPEND("Stack buffer header:%s", "\n");
375 SAFE_APPEND(" allocated at: [%s]:%d\n", header->func, header->line);
376 SAFE_APPEND(" total size: %zu bytes\n", header->total_size);
377 SAFE_APPEND(" extra size: %zu bytes (%.0f%% of user size)\n", header->extra_size,
379 SAFE_APPEND(" magic offset: %zu\n", header->magic_addr_offset);
380 SAFE_APPEND(" last ptr: %p\n", header->last_ptr);
381 lmmp_abort(LAMMP_ERROR_OUT_OF_BOUNDS, error_buf, func, line);
382 }
383
384 void* old_top = stack_get_top_func();
385 void* new_top = (mp_byte_t*)old_top - total_size;
386 if (new_top < lmmp_stack_begin || new_top > lmmp_stack_end) {
387 char msg[192];
388 snprintf(msg, sizeof(msg), "Stack underflow (free: %p, size: %zu; stack start: %p, end: %p)", ptr,
389 (mp_byte_t*)magic_addr - (mp_byte_t*)ptr, lmmp_stack_begin, lmmp_stack_end);
391 }
392
393 if (new_top != lmmp_stack_begin) {
394 if ((mp_byte_t*)new_top + HEADER_SIZE > (mp_byte_t*)lmmp_stack_end) {
395 lmmp_abort(LAMMP_ERROR_MEMORY_FREE_FAILURE, "Invalid previous block header", func, line);
396 }
397 }
398 stack_set_top_func(new_top);
399}
400#endif // LAMMP_DEBUG_MEMORY_CHECK != 1
401
404}
405
uint8_t mp_byte_t
Definition lmmp.h:210
#define LAMMP_MAX_ALIGN
Definition lmmp.h:219
void lmmp_abort(lmmp_error_t type, const char *msg, const char *func, int line)
LAMMP 全局退出函数,内部错误或断言失败时调用,若设置了全局退出函数,则会调用该函数,否则会调用默认的退出函数。
Definition abort.c:42
#define LAMMP_THREAD_LOCAL
Definition lmmp.h:237
#define LAMMP_MEMORY_MORE_ALLOC_TIMES
Definition lmmp.h:54
@ LAMMP_ERROR_MEMORY_ALLOC_FAILURE
Definition lmmp.h:136
@ LAMMP_ERROR_MEMORY_LEAK
Definition lmmp.h:139
@ LAMMP_ERROR_MEMORY_FREE_FAILURE
Definition lmmp.h:137
@ LAMMP_ERROR_OUT_OF_BOUNDS
Definition lmmp.h:138
#define LMMP_ROUND_UP_MULTIPLE(a, m)
Definition lmmp.h:361
#define lmmp_leak_tracker
Definition lmmp.h:316
void * lmmp_stack_alloc(size_t size)
栈内存分配函数(使用stack_get_top和stack_set_top)
Definition memory.c:218
void lmmp_temp_heap_free_(void *marker)
临时堆内存释放函数
Definition memory.c:104
void lmmp_set_heap_allocator(const lmmp_heap_allocator_t *heap)
设置 LAMMP 全局堆内存分配函数
Definition memory.c:76
#define stack_set_top_func(top)
Definition memory.c:37
#define heap_alloc_func
Definition memory.c:26
void * lmmp_alloc(size_t size)
内存分配函数(调用lmmp_heap_alloc_fn)
Definition memory.c:166
void * lmmp_temp_heap_alloc_(void **pmarker, size_t size)
临时堆内存分配函数
Definition memory.c:91
void lmmp_stack_free(void *ptr)
栈内存释放函数(使用stack_get_top和stack_set_top)
Definition memory.c:238
_Thread_local void * lmmp_stack_begin
Definition memory.c:32
void lmmp_stack_reset(size_t size)
LAMMP 全局栈重置函数(通常不需要手动调用)
Definition memory.c:39
void lmmp_free(void *ptr)
内存释放函数(调用lmmp_heap_free_fn)
Definition memory.c:204
void * lmmp_realloc(void *oldptr, size_t new_size)
内存重分配函数(调用lmmp_realloc_fn)
Definition memory.c:186
_Thread_local void * lmmp_stack_top
Definition memory.c:34
#define stack_get_top_func()
Definition memory.c:36
#define realloc_func
Definition memory.c:28
static _Thread_local int heap_alloc_count
Definition memory.c:30
_Thread_local void * lmmp_stack_end
Definition memory.c:33
#define heap_free_func
Definition memory.c:27
void lmmp_global_init(void)
全局初始化函数(线程局部的)
Definition memory.c:402
void lmmp_global_deinit(void)
(线程局部的)全局共享的动态分配的堆内存资源释放函数
Definition memory.c:406
#define HSIZE
Definition memory.c:18
#define SIZE_SIZE
Definition memory.c:216
static _Thread_local lmmp_heap_allocator_t global_heap
Definition memory.c:20
static void lmmp_chech_memory(size_t size, const char *func, int line)
Definition memory.c:117
void lmmp_stack_init(void)
LAMMP 全局栈初始化函数(通常不需要手动调用)
Definition memory.c:66
int lmmp_alloc_count(int cnt)
堆内存分配计数器(线程局部)
Definition memory.c:123
#define LAMMP_DEFAULT_STACK_SIZE
Definition mparam.h:23
void lmmp_prime_int_table_free_(void)
释放全局素数表
#define SAFE_APPEND(...)
static void * lmmp_realloc_debug(void *ptr, size_t new_size, const char *func, int line)
static void * lmmp_alloc_debug(size_t size, const char *func, int line)
static void lmmp_free_debug(void *ptr, const char *func, int line)