From 662d632ed27645cb1153846d7ef68e6312083760 Mon Sep 17 00:00:00 2001 From: guoheng Date: Mon, 16 Mar 2026 20:03:37 +0800 Subject: [PATCH 1/5] Modify mempool.h to fit format. --- lib/mempool.h | 317 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/xy.h | 51 ++++---- 2 files changed, 344 insertions(+), 24 deletions(-) create mode 100644 lib/mempool.h diff --git a/lib/mempool.h b/lib/mempool.h new file mode 100644 index 00000000..644de937 --- /dev/null +++ b/lib/mempool.h @@ -0,0 +1,317 @@ +#ifndef MEM_POOL +#define MEM_POOL + + +#include + + +/* 对齐到指针大小的倍数 */ +#define ALIGN(n) (((n) + sizeof(void*) - 1) & ~(sizeof(void*) - 1)) +/* 每次扩容新段的最小大小 */ +#define EXPAND_MIN 4096 +/* 从用户指针回退到 BlockHeader */ +#define HDR(ptr) ((BlockHeader *)((char *)(ptr) - sizeof(BlockHeader))) +/* 一次完整分配需要的总字节:header + 数据区 */ +#define TOTAL(sz) (sizeof(BlockHeader) + (sz)) + + +/* + * 块头:紧贴在每块分配数据的前面,记录本块数据区的对齐后大小。 + * 用户拿到的指针指向 header 之后;mp_free / mp_realloc 向前偏移 + * sizeof(BlockHeader) 读回大小,无需调用方手动传 size。 + */ +typedef struct BlockHeader { + size_t size; /* 数据区对齐后大小(不含 header 本身) */ +} BlockHeader; + +/* 空闲链表节点(直接复用已释放块的内存空间) */ +typedef struct FreeBlock { + struct FreeBlock *next; /* 方便地插入删除 */ + size_t size; /* 数据区大小,含义同 BlockHeader.size */ +} FreeBlock; + +/* 内存池段;多段通过 next 链接,实现自动扩容 */ +typedef struct MemPool { + void *buffer; /* 线性缓冲区起始地址 */ + size_t buf_size; /* 缓冲区总大小 */ + size_t used; /* 已使用字节数(header + 数据 + 对齐) */ + FreeBlock *free_list; /* 已释放块的单链表 */ + struct MemPool *next; /* 扩容后追加的下一段 */ +} MemPool; + + +static MemPool *_mp_create (size_t initial_size); +static void *_mp_malloc (MemPool *pool, size_t size); +static void *_mp_calloc (MemPool *pool, size_t nmemb, size_t size); +static void *_mp_realloc(MemPool *pool, void *ptr, size_t new_size); +static void _mp_free (MemPool *pool, void *ptr); +static void _mp_destroy(MemPool *pool); + + +static MemPool* global_pool; + +/* ------------------------------------------------------------------ */ +/* 内部:创建一个新的池段 */ +/* ------------------------------------------------------------------ */ +static MemPool * +_new_segment (size_t size) +{ + MemPool *seg = (MemPool *)malloc(sizeof(MemPool)); + if (!seg) { return NULL; } + seg->buffer = malloc(size); + if (!seg->buffer) { free(seg); return NULL; } + seg->buf_size = size; + seg->used = 0; + seg->free_list = NULL; + seg->next = NULL; + return seg; +} + +/* ------------------------------------------------------------------ */ +/* 内部:核心分配(返回数据区指针,已写好 BlockHeader) */ +/* ------------------------------------------------------------------ */ +static void * +_do_alloc (MemPool *pool, size_t size) +{ + /* size 已由调用方对齐 */ + size_t total = TOTAL(size); + + /* 1. 空闲链表复用 */ + MemPool *seg = pool; + while (seg) + { + FreeBlock **prev = &seg->free_list; + FreeBlock *blk = seg->free_list; + while (blk) + { + if (blk->size >= size) + { + *prev = blk->next; + /* 写入 header,返回数据区 */ + BlockHeader *hdr = (BlockHeader *)blk; + hdr->size = size; + return (char *)hdr + sizeof(BlockHeader); + } + prev = &blk->next; /* &blk->next == blk->prev because: 1 of struct is next */ + blk = blk->next; + } + seg = seg->next; + } + + /* 2. 线性区顺序分配 */ + MemPool *last = pool; + seg = pool; + while (seg) + { + if (seg->used + total <= seg->buf_size) { + BlockHeader *hdr = (BlockHeader *)((char *)seg->buffer + seg->used); + hdr->size = size; + seg->used += total; + return (char *)hdr + sizeof(BlockHeader); + } + last = seg; + seg = seg->next; + } + + /* 3. 扩容:追加新段 */ + size_t new_size = (total > EXPAND_MIN) ? total * 2 : EXPAND_MIN; + MemPool *new_seg = _new_segment(new_size); + if (!new_seg) { return NULL; } + last->next = new_seg; + + BlockHeader *hdr = (BlockHeader *)new_seg->buffer; + hdr->size = size; + new_seg->used = total; + return (char *)hdr + sizeof(BlockHeader); +} + +/** + * @brief 创建一个新的内存池 + * + * @param initial_size 初始分配的大小(字节)。如果小于内部最小阈值,将自动调整为最小值。 + * + * @return 成功返回指向新内存池的指针,失败返回 NULL(通常在内存不足时)。 + */ +MemPool * +_mp_create (size_t initial_size) +{ + if (initial_size < EXPAND_MIN) initial_size = EXPAND_MIN; + + return _new_segment(initial_size); +} + +/** + * @brief 从内存池中分配指定大小的内存块 + * + * @param pool 指向内存池的指针 + * @param size 需要分配的字节数 + * + * @return 成功返回指向已分配内存的指针,失败返回 NULL(如 pool 为空、size 为 0 或内存不足)。 + * 返回的内存未初始化。 + */ +void * +_mp_malloc (MemPool *pool, size_t size) +{ + if (!pool || size == 0) { return NULL; } + + return _do_alloc(pool, ALIGN(size)); +} + +/** + * @brief 从内存池中分配并清零指定大小的内存块 + * + * @param pool 指向内存池的指针 + * @param nmemb 元素个数 + * @param size 每个元素的字节数 + * + * @return 成功返回指向已分配且清零内存的指针,失败返回 NULL。 + * 若发生整数溢出(nmemb * size 超出范围)也会返回 NULL。 + */ +void * +_mp_calloc (MemPool *pool, size_t nmemb, size_t size) +{ + if (!pool || nmemb == 0 || size == 0) { return NULL; } + /* 溢出检查 */ + if (size != 0 && nmemb > (size_t)-1 / size) { return NULL; } + + size_t total = nmemb * size; + void *ptr = _do_alloc(pool, ALIGN(total)); + if (ptr) memset(ptr, 0, total); + return ptr; +} + +/** + * @brief 调整内存块的大小 + * + * @param pool 指向内存池的指针 + * @param ptr 指向之前分配的内存块的指针。若为 NULL,则行为等同于 mp_alloc。 + * @param new_size 新的请求大小(字节)。若为 0,则行为等同于 mp_free 并返回 NULL。 + * + * @return 成功返回指向新内存块的指针(可能已移动),失败返回 NULL。 + * 若缩小或大小不变,通常原地返回;若扩大,则分配新块、拷贝数据并释放旧块。 + */ +void * +_mp_realloc (MemPool *pool, void *ptr, size_t new_size) +{ + /* realloc(pool, NULL, n) → alloc */ + if (!ptr) { return _mp_malloc(pool, new_size); } + /* realloc(pool, ptr, 0) → free */ + if (new_size == 0) { _mp_free(pool, ptr); return NULL; } + + size_t aligned_new = ALIGN(new_size); + size_t old_size = HDR(ptr)->size; /* 读取块头记录的旧大小 */ + + /* 缩小或等大:原地返回,更新 header */ + if (aligned_new <= old_size) + { + HDR(ptr)->size = aligned_new; + return ptr; + } + + /* 扩大:重新分配 + 拷贝 + 释放旧块 */ + void *new_ptr = _do_alloc(pool, aligned_new); + if (!new_ptr) { return NULL; } + memcpy(new_ptr, ptr, old_size); + _mp_free(pool, ptr); + return new_ptr; +} + +/** + * @brief 释放之前分配的内存块回内存池 + * + * @param pool 指向内存池的指针 + * @param ptr 指向要释放的内存块的指针。若为 NULL 或 pool 为 NULL,则直接返回。 + * + * @note 该操作并非真正归还给操作系统,而是将块标记为空闲并加入空闲链表,供后续分配复用。 + */ +void +_mp_free (MemPool *pool, void *ptr) +{ + if (!pool || !ptr) return; + BlockHeader *hdr = HDR(ptr); /* 从块头读出大小 */ + FreeBlock *blk = (FreeBlock *)hdr; /* 复用同一块内存做链表节点 */ + blk->size = hdr->size; + blk->next = pool->free_list; /* 头插法插入free_list */ + pool->free_list = blk; +} + +/** + * @brief 销毁内存池并释放所有相关资源 + * + * @param pool 指向要销毁的内存池的指针 + * + * @note 此函数会释放内存池管理的所有内存段(buffer)以及池结构体本身。 + * 调用后不应再使用该 pool 指针或其曾分配的任何指针。 + */ +void +_mp_destroy (MemPool *pool) +{ + MemPool *seg = pool; + while (seg) + { + MemPool *next = seg->next; + free(seg->buffer); + free(seg); + seg = next; + } +} + +/** + * @brief 初始化内存池 + * + * @param size 初始化内存池的大小 + * + * @note 此函数在程序开始时调用,请不要在其他时刻调用 + */ + +__attribute__((constructor)) +void +mp_initialize (size_t size) +{ + MemPool *pool = _mp_create(size); + global_pool = pool; +} + +/** + * @brief 销毁内存池并释放所有相关资源 + * + * @param None + * + * @note 此函数在程序结束时调用,请不要在其他时刻调用 + */ +__attribute__((destructor)) +void +mp_finalize (void) +{ + _mp_destroy(global_pool); +} + + +/* ------------------------------------------------------------------ */ +/* API */ +/* ------------------------------------------------------------------ */ +void * +mp_malloc (size_t size) +{ + return _mp_malloc(global_pool,size); +} + +void * +mp_calloc (size_t nmemb, size_t size) +{ + return _mp_calloc(global_pool,nmemb,size); +} + +void * +mp_realloc (void *ptr, size_t new_size) +{ + return _mp_realloc(global_pool,ptr,new_size); +} + +void +mp_free (void *ptr) +{ + _mp_free(global_pool,ptr); +} + +#endif diff --git a/lib/xy.h b/lib/xy.h index 6d706642..5a26eeb8 100644 --- a/lib/xy.h +++ b/lib/xy.h @@ -47,6 +47,8 @@ #include #include // opendir() closedir() +#include "mempool.h" + #if defined(__STDC__) && __STDC_VERSION__ >= 202311 #define XY_Deprecate_This(msg) [[deprecated(msg)]] #elif defined(__GNUC__) || defined(__clang__) @@ -215,9 +217,10 @@ void p (const char *s) { printf ("%s\n", s); } static inline void * xy_malloc0 (size_t size) { - void *ptr = malloc (size); - memset (ptr, 0, size); - return ptr; + // void *ptr = malloc (size); + // memset (ptr, 0, size); + // return ptr; + return mp_calloc(size,1); } @@ -234,7 +237,7 @@ xy_ptr_replace (char **pptr, char *new_mem) xy_cant_be_null (pptr); if (*pptr) - free (*pptr); + mp_free (*pptr); *pptr = new_mem; } @@ -283,7 +286,7 @@ xy_str_gsub (const char *str, const char *pat, const char *replace) } // puti(count); DEBUG 匹配次数 - char *ret = malloc (unit * count + len + 1); + char *ret = mp_malloc (unit * count + len + 1); char *retcur = ret; cur = str; @@ -317,7 +320,7 @@ xy_2strcat (const char *str1, const char *str2) { size_t len = strlen (str1); size_t size = len + strlen (str2) + 1; - char *ret = malloc (size); + char *ret = mp_malloc (size); strcpy (ret, str1); strcpy (ret + len, str2); return ret; @@ -343,7 +346,7 @@ static char * xy_strcat (unsigned int count, ...) { size_t al_fixed = 256; - char *ret = calloc (1, al_fixed); + char *ret = mp_calloc (1, al_fixed); // 已分配次数 int al_times = 1; // 当前已分配量 @@ -375,7 +378,7 @@ xy_strcat (unsigned int count, ...) if (need_realloc) { ptrdiff_t diff = cur - ret; - ret = realloc (ret, al_cur); + ret = mp_realloc (ret, al_cur); cur = ret + diff; } if (NULL == ret) @@ -489,7 +492,7 @@ _xy_str_to_terminal_style (int style, const char *str) new_str: // -2 把中间%s减掉 len = strlen (color_fmt_str) - 2; - char *buf = malloc (strlen (str) + len + 1); + char *buf = mp_malloc (strlen (str) + len + 1); sprintf (buf, color_fmt_str, str); return buf; } @@ -755,7 +758,7 @@ xy_file_read (const char *path) if (read_bytes < (size_t) size && ferror (fp)) { fclose (fp); - free (buf); + mp_free (buf); return xy_strdup (""); } @@ -765,7 +768,7 @@ xy_file_read (const char *path) char *formatted_str = xy_str_gsub (buf, "\r\n", "\n"); xy_ptr_replace (&formatted_str, xy_str_gsub (formatted_str, "\r", "\n")); - free (buf); + mp_free (buf); return formatted_str; } @@ -833,7 +836,7 @@ _xy_log (int level, const char *prompt, const char *content) { puts (str); } - free (str); + mp_free (str); } @@ -858,7 +861,7 @@ xy_log_brkt_to (const char *prompt, const char *content, FILE *stream) { char *str = xy_strcat (4, "[", prompt, "] ", content); fprintf (stream, "%s\n", str); - free (str); + mp_free (str); } #define xy_log_brkt(prompt1,prompt2,content) _xy_log_brkt(_XY_Log_Plain, prompt1,prompt2,content) @@ -919,7 +922,7 @@ _xy_log_brkt (int level, const char *prompt1, const char *prompt2, const char *c { puts (str); } - free (str); + mp_free (str); } @@ -963,7 +966,7 @@ static char * xy_run_iter_lines (const char *cmd, unsigned long n, bool (*func) (const char *)) { const int size = 512; - char *buf = (char *) malloc (size); + char *buf = (char *) mp_malloc (size); FILE *stream = popen (cmd, "r"); if (stream == NULL) @@ -1051,7 +1054,7 @@ xy_run_get_stdout (const char *cmd, char **output) if (size == cap) { cap *= 2; - char *new_buf = realloc (buf, cap); + char *new_buf = mp_realloc (buf, cap); buf = new_buf; } } @@ -1137,7 +1140,7 @@ _xy_win_powershell_profile () { char *documents_dir = _xy_win_documents (); char *profile_path = xy_2strcat (documents_dir, "\\PowerShell\\Microsoft.PowerShell_profile.ps1"); - free (documents_dir); + mp_free (documents_dir); return profile_path; } else @@ -1157,7 +1160,7 @@ _xy_win_powershellv5_profile () { char *documents_dir = _xy_win_documents (); char *profile_path = xy_2strcat (documents_dir, "\\WindowsPowerShell\\Microsoft.PowerShell_profile.ps1"); - free (documents_dir); + mp_free (documents_dir); return profile_path; } else @@ -1185,7 +1188,7 @@ xy_file_exist (const char *path) // 0 即 F_OK bool result = (0 == access (check_path, 0)) ? true : false; - if (expanded_path) free (expanded_path); + if (expanded_path) mp_free (expanded_path); return result; } @@ -1227,7 +1230,7 @@ xy_dir_exist (const char *path) { result = false; } - if (allocated_dir) free (allocated_dir); + if (allocated_dir) mp_free (allocated_dir); return result; #endif } @@ -1235,9 +1238,9 @@ xy_dir_exist (const char *path) { char *tmp_cmd = xy_2strcat ("test -d ", dir); int status = system (tmp_cmd); - free (tmp_cmd); + mp_free (tmp_cmd); bool result = (0==status); - if (allocated_dir) free (allocated_dir); + if (allocated_dir) mp_free (allocated_dir); return result; } @@ -1263,7 +1266,7 @@ xy_normalize_path (const char *path) { char *tmp = xy_str_delete_prefix (new, "~"); char *joined = xy_2strcat (xy_os_home, tmp); - free (tmp); + mp_free (tmp); xy_ptr_replace (&new, joined); } @@ -1588,7 +1591,7 @@ xy_seq_pop (XySeq_t *seq) seq->length--; void *data = l->data; - free (l); + mp_free (l); return data; } From 6979f6d0c6ef5c6ece7585476c928d83a445b3b5 Mon Sep 17 00:00:00 2001 From: guoheng Date: Mon, 16 Mar 2026 20:34:28 +0800 Subject: [PATCH 2/5] Modify header for files in lib --- lib/mempool.h | 14 ++++++++++++++ lib/xy.h | 4 ++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/mempool.h b/lib/mempool.h index 644de937..bc968921 100644 --- a/lib/mempool.h +++ b/lib/mempool.h @@ -1,3 +1,17 @@ +/** ------------------------------------------------------------ + * Copyright © 2023-2026 曾奥然, 郭恒 + * SPDX-License-Identifier: MIT + * ------------------------------------------------------------- + * Lib Authors : 郭恒 <2085471348@qq.com> + * Contributors : + * Created On : <2026-03-16> + * Last Modified : <2026-03-16> + * + * + * mp(mempool): 内存池 + * + * 为xy.h准备的无内存泄露的实用函数 (utilities) + * ------------------------------------------------------------*/ #ifndef MEM_POOL #define MEM_POOL diff --git a/lib/xy.h b/lib/xy.h index 5a26eeb8..60313c2e 100644 --- a/lib/xy.h +++ b/lib/xy.h @@ -1,5 +1,5 @@ /** ------------------------------------------------------------ - * Copyright © 2023-2026 曾奥然, 郭恒 + * Copyright © 2026-2026 曾奥然, 郭恒 * SPDX-License-Identifier: MIT * ------------------------------------------------------------- * Lib Authors : 曾奥然 @@ -9,7 +9,7 @@ * | BingChunMoLi * | * Created On : <2023-08-28> - * Last Modified : <2025-12-31> + * Last Modified : <2026-03-16> * * * xy: 襄阳、咸阳 From fdefa8543e248474474f0af55bf7e9a125e5170c Mon Sep 17 00:00:00 2001 From: guoheng Date: Mon, 16 Mar 2026 20:50:45 +0800 Subject: [PATCH 3/5] Fix bug about 'core dump' when 'chsrc ls ruby' --- src/chsrc-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chsrc-main.c b/src/chsrc-main.c index c823d20c..83ec81da 100644 --- a/src/chsrc-main.c +++ b/src/chsrc-main.c @@ -372,7 +372,7 @@ cli_print_target_features (Target_t *target, const char *input_target_name) default: xy_unreached(); } - char *msg = xy_strcat (3, bdblue (" = "), + char *msg = xy_strcat (2, bdblue (" = "), purple (xy_strcat (5, "默认作用域 | chsrc set -scope=default ", input_target_name, " (= ", default_scope_name ,")"))); puts (msg); br(); From 4039fbe7b5b146b55276fff6561ebf4eed948bab Mon Sep 17 00:00:00 2001 From: guoheng Date: Mon, 16 Mar 2026 21:16:19 +0800 Subject: [PATCH 4/5] Modify date in copyright at xy.h and mempool.h --- lib/mempool.h | 2 +- lib/xy.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mempool.h b/lib/mempool.h index bc968921..07295f9e 100644 --- a/lib/mempool.h +++ b/lib/mempool.h @@ -1,5 +1,5 @@ /** ------------------------------------------------------------ - * Copyright © 2023-2026 曾奥然, 郭恒 + * Copyright © 2026-2026 曾奥然, 郭恒 * SPDX-License-Identifier: MIT * ------------------------------------------------------------- * Lib Authors : 郭恒 <2085471348@qq.com> diff --git a/lib/xy.h b/lib/xy.h index 60313c2e..06cbcebf 100644 --- a/lib/xy.h +++ b/lib/xy.h @@ -1,5 +1,5 @@ /** ------------------------------------------------------------ - * Copyright © 2026-2026 曾奥然, 郭恒 + * Copyright © 2023-2026 曾奥然, 郭恒 * SPDX-License-Identifier: MIT * ------------------------------------------------------------- * Lib Authors : 曾奥然 From 1ee7b3c9969d4e017035ca33ca5536ae53421950 Mon Sep 17 00:00:00 2001 From: guoheng Date: Mon, 16 Mar 2026 21:32:24 +0800 Subject: [PATCH 5/5] Comment free in fw.c --- src/framework/core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/framework/core.c b/src/framework/core.c index d2ca0004..bca2e6a1 100644 --- a/src/framework/core.c +++ b/src/framework/core.c @@ -853,7 +853,7 @@ measure_speed_for_every_source (Source_t sources[], int size, double speed_recor speed_records[i] = speed; /* 释放 url 内存 */ - if (url) free (url); + // if (url) free (url); } else { @@ -1566,7 +1566,7 @@ chsrc_run_as_bash_file (const char *script_content) char *cmd = xy_2strcat ("bash ", tmpfile); chsrc_run (cmd, RunOpt_Dont_Abort_On_Failure); remove (tmpfile); - free (tmpfile); /* 释放 tmpfile 路径内存 */ + // free (tmpfile); /* 释放 tmpfile 路径内存 */ } @@ -1587,7 +1587,7 @@ chsrc_run_as_sh_file (const char *script_content) char *cmd = xy_2strcat ("sh ", tmpfile); chsrc_run (cmd, RunOpt_Dont_Abort_On_Failure); remove (tmpfile); - free (tmpfile); + // free (tmpfile); } @@ -1607,7 +1607,7 @@ chsrc_run_as_pwsh_file (const char *script_content) char *cmd = xy_2strcat ("pwsh ", tmpfile); chsrc_run (cmd, RunOpt_Dont_Abort_On_Failure); remove (tmpfile); - free (tmpfile); + // free (tmpfile); } @@ -1628,7 +1628,7 @@ chsrc_run_as_powershellv5_file (const char *script_content) char *cmd = xy_2strcat ("powershell -File ", tmpfile); chsrc_run (cmd, RunOpt_Dont_Abort_On_Failure); remove (tmpfile); - free (tmpfile); + // free (tmpfile); }