修复了一个malloc的问题

This commit is contained in:
2026-09-18 17:46:46 +08:00
parent 2553f30fb8
commit acd29d76d9
9 changed files with 941 additions and 37 deletions
+55 -26
View File
@@ -8,7 +8,11 @@
* 创建日期:2026-09-14
* 修改记录:
* v1.0 2026-09-14 王建锋 创建初始版本(P3:段键表引擎 + net_cfg 集成)
* 函数说明:引擎状态非重入——调用方须收敛同一任务(netTask:poll/save;
* v1.1 2026-09-18 王建锋 P0-1:临时缓冲改经 cfg_store_alloc(MCU = FreeRTOS 堆),
* 移除对 C 库 malloc 的全部依赖(MicroLIB C 堆仅 512B,
* 原 4 处 KB 级 malloc 真机必然失败);增编译期堆峰值预算
* 校验 + 失败上报自检记录
* 函数说明:引擎状态非重入——调用方须收敛同一任务(defaultTask:poll/save,见 P1-3;
* 启动期 load 先于任务竞争);FS 卷并发由 FatFS REENTRANT 卷锁保证
* (见《配置文件设计说明》D15 A+ 方案)
*/
@@ -16,7 +20,7 @@
/* 头文件包含区 */
#include <string.h>
#include <stdlib.h>
#include <stdlib.h> /* strtoul(键值解码);堆分配一律走 cfg_store_alloc,禁 malloc */
#include <stdio.h>
@@ -26,6 +30,8 @@
#include "cfg_file_store.h"
#include "sys_log.h" /* 配置读写失败上报自检记录(双端共享接口,MCU 端 preboot/队列安全) */
#define DBG_TAG "[CFG]"
#include "dbg_log.h"
@@ -41,10 +47,17 @@ static const char s_doc_header[] =
"; - 编辑后经 FTP 上传或设备端保存,设备 4s 沉降后自动重载\r\n"
"; ============================================================\r\n";
#define CFG_OUT_MAX 5120u /* 保存输出缓冲(输入复用读缓冲;堆峰值 ≈ 9KB 暂态) */
#define CFG_OUT_MAX 5120u /* 保存输出缓冲上限(经 cfg_store_alloc 取,见下方堆峰值预算) */
#define CFG_LINE_TEST_MAX 127u /* 受管键行匹配的行长上限(超长必非受管键行) */
#define CFG_SNAP_MAX 64u /* 变更检测段快照缓冲(挂回调段 data_size 须 ≤ 此值) */
#define CFG_NAME_MAX 16u /* 段名缓冲(15 字符 + NUL) */
#define CFG_HEAP_BUDGET 10240u /* 暂态堆峰值预算:读缓冲(1B NUL) + 输出缓冲之和上限 */
/* 编译期钉死暂态堆峰值:放大 CFG_FILE_MAX_LEN / CFG_OUT_MAX 会先在此编译失败,强制
* 改动者重新核对平台堆余量(MCU = FreeRTOS 堆,当前实测余量见《RAM使用分析与优化方案》),
* 而不是在真机上退化成运行期分配失败。用 typedef 负数组实现(ARMCC 5 C99 无 C11
* _Static_assert);当前峰值 4097 + 5120 = 9217B ≤ 10240B */
typedef char cfg_heap_peak_check_t[(CFG_FILE_MAX_LEN + 1u + CFG_OUT_MAX) <= CFG_HEAP_BUDGET ? 1 : -1];
/* 静态变量定义区 */
@@ -467,11 +480,11 @@ static int s_gen_document(char *p_buf, size_t cap, size_t *p_len) {
}
/*
* 函数功能:读配置文件到堆缓冲(NUL 结尾)
* 函数功能:读配置文件到平台堆缓冲(NUL 结尾)
* 入口参数:p_pbuf - 缓冲指针输出 uint8_t **
* p_len - 实际长度输出 size_t *
* 返回值:0 - 成功;-1 - 分配/读失败(缓冲已释放) int
* 限定条件:成功时调用方须 free(*p_pbuf)
* 限定条件:成功时调用方须 cfg_store_free(*p_pbuf)(MCU = FreeRTOS 堆,勿用 C 库 free)
*/
static int s_load_file(uint8_t **p_pbuf, size_t *p_len) {
uint8_t *p_buf;
@@ -482,14 +495,15 @@ static int s_load_file(uint8_t **p_pbuf, size_t *p_len) {
return -1;
}
*p_pbuf = NULL;
p_buf = (uint8_t *)malloc(CFG_FILE_MAX_LEN + 1u);
p_buf = (uint8_t *)cfg_store_alloc(CFG_FILE_MAX_LEN + 1u);
if (p_buf == NULL) {
DBG_ERROR("read: malloc %uB FAIL", (unsigned)(CFG_FILE_MAX_LEN + 1u));
DBG_ERROR("read: alloc %uB FAIL (heap free %uB)",
(unsigned)(CFG_FILE_MAX_LEN + 1u), (unsigned)cfg_store_heap_free());
return -1;
}
r = cfg_store_read(cfg_store_config_path(), p_buf, CFG_FILE_MAX_LEN, &nread);
if (r != 0) {
free(p_buf);
cfg_store_free(p_buf);
return -1;
}
p_buf[nread] = '\0';
@@ -519,19 +533,24 @@ static int s_write_doc(const uint8_t *p_buf, size_t len) {
* 限定条件:各段 RAM 副本须为期望落盘值
*/
static int s_write_template(void) {
char *p_buf = (char *)malloc(CFG_OUT_MAX);
char *p_buf = (char *)cfg_store_alloc(CFG_OUT_MAX);
size_t len = 0u;
int r;
if (p_buf == NULL) {
DBG_ERROR("template: malloc %uB FAIL", (unsigned)CFG_OUT_MAX);
DBG_ERROR("template: alloc %uB FAIL (heap free %uB)",
(unsigned)CFG_OUT_MAX, (unsigned)cfg_store_heap_free());
syslog_post(SYSLOG_SELFTEST, "cfg heap alloc fail");
return -1;
}
r = s_gen_document(p_buf, CFG_OUT_MAX, &len);
if (r == 0) {
r = s_write_doc((const uint8_t *)p_buf, len);
if (r != 0) {
syslog_post(SYSLOG_SELFTEST, "cfg template write fail");
}
}
free(p_buf);
cfg_store_free(p_buf);
return r;
}
@@ -979,11 +998,13 @@ int cfg_file_load(void) {
if (s_load_file(&p_buf, &len) != 0) {
DBG_ERROR("load: file read FAIL, factory defaults kept");
syslog_post(SYSLOG_SELFTEST, "cfg load read fail");
return -1;
}
s_parse((char *)p_buf, -1);
free(p_buf);
DBG_INFO("load: OK (%luB)", (unsigned long)st.size);
cfg_store_free(p_buf);
DBG_INFO("load: OK (%luB, heap free %uB)",
(unsigned long)st.size, (unsigned)cfg_store_heap_free());
return 0;
}
}
@@ -1030,42 +1051,50 @@ int cfg_file_save(void) {
if (s_load_file(&p_in, &in_len) != 0) {
DBG_ERROR("save: file read FAIL");
syslog_post(SYSLOG_SELFTEST, "cfg save read fail");
return -1;
}
/* Pass 1 在独立副本上切分(避免破坏原文的行结束符);
* 副本在 p_out 分配前释放,堆峰值维持 p_in + p_out(约 9KB) */
p_in1 = (uint8_t *)malloc(in_len + 1u);
* 副本在 p_out 分配前释放,堆峰值维持 p_in + p_out(≤ CFG_HEAP_BUDGET,
* 编译期已校验,见文件常量区) */
p_in1 = (uint8_t *)cfg_store_alloc(in_len + 1u);
if (p_in1 == NULL) {
free(p_in);
DBG_ERROR("save: malloc %uB FAIL", (unsigned)(in_len + 1u));
cfg_store_free(p_in);
DBG_ERROR("save: alloc %uB FAIL (heap free %uB)",
(unsigned)(in_len + 1u), (unsigned)cfg_store_heap_free());
syslog_post(SYSLOG_SELFTEST, "cfg heap alloc fail");
return -1;
}
(void)memcpy(p_in1, p_in, in_len + 1u);
s_surgical_pass1((char *)p_in1);
free(p_in1);
cfg_store_free(p_in1);
p_out = (char *)malloc(CFG_OUT_MAX);
p_out = (char *)cfg_store_alloc(CFG_OUT_MAX);
if (p_out == NULL) {
free(p_in);
DBG_ERROR("save: malloc %uB FAIL", (unsigned)CFG_OUT_MAX);
cfg_store_free(p_in);
DBG_ERROR("save: alloc %uB FAIL (heap free %uB)",
(unsigned)CFG_OUT_MAX, (unsigned)cfg_store_heap_free());
syslog_post(SYSLOG_SELFTEST, "cfg heap alloc fail");
return -1;
}
r = s_surgical((char *)p_in, in_len, p_out, CFG_OUT_MAX, &out_len);
free(p_in);
cfg_store_free(p_in);
if (r != 0) {
free(p_out);
cfg_store_free(p_out);
DBG_ERROR("save: output overflow, aborted (file untouched)");
syslog_post(SYSLOG_SELFTEST, "cfg save overflow");
return -1;
}
r = s_write_doc((const uint8_t *)p_out, out_len);
free(p_out);
cfg_store_free(p_out);
if (r != 0) {
DBG_ERROR("save: file write FAIL");
syslog_post(SYSLOG_SELFTEST, "cfg save write fail");
return -1;
}
DBG_INFO("save: OK (surgical, %uB -> %uB)", (unsigned)in_len, (unsigned)out_len);
@@ -1120,7 +1149,7 @@ void cfg_file_poll(void) {
}
if (len > CFG_FILE_MAX_LEN) {
free(p_buf);
cfg_store_free(p_buf);
for (i = 0; i < (int)CFG_FILE_MAX_SECTIONS; i++) {
if (s_sections[i].used != 0) {
(void)memcpy(s_sections[i].p_data, s_sections[i].p_defaults,
@@ -1152,7 +1181,7 @@ void cfg_file_poll(void) {
s_parse((char *)p_buf, i);
}
}
free(p_buf);
cfg_store_free(p_buf);
DBG_INFO("poll: config file reloaded");
}
+27
View File
@@ -32,6 +32,33 @@ typedef struct {
uint32_t mtime;
} cfg_file_stat_t;
/*
* 函数功能:分配共享核心临时缓冲(由平台后端提供:MCU = FreeRTOS 堆 pvPortMalloc,
* 模拟器 = 宿主 CRT malloc)
* 入口参数:size - 字节数 size_t
* 返回值:缓冲指针(内容未清零);失败返回 NULL void *
* 限定条件:必须与 cfg_store_free 配对;共享核心(cfg_file.c / net_cfg.c)禁止直接
* 调用 C 库 malloc——MCU 端 MicroLIB C 堆仅 512 B(startup Heap_Size=0x200),
* KB 级分配必然失败,一律经本接口取 FreeRTOS 堆
*/
void *cfg_store_alloc(size_t size);
/*
* 函数功能:释放 cfg_store_alloc 分配的临时缓冲
* 入口参数:p_buf - 缓冲指针(NULL 安全) void *
* 返回值:无
* 限定条件:p_buf 必须来自 cfg_store_alloc(不得跨分配器释放、不得释放栈地址)
*/
void cfg_store_free(void *p_buf);
/*
* 函数功能:当前空闲堆字节数(分配失败诊断用,非精确预算)
* 入口参数:无
* 返回值:空闲字节数;模拟器不跟踪宿主堆,恒返回 0 uint32_t
* 限定条件:无
*/
uint32_t cfg_store_heap_free(void);
/*
* 函数功能:读文件(最多 cap 字节)
* 入口参数:p_path - 文件路径 const char *
+38
View File
@@ -8,11 +8,15 @@
* 创建日期:2026-09-14
* 修改记录:
* v1.0 2026-09-14 王建锋 创建初始版本
* v1.1 2026-09-18 王建锋 增 cfg_store_alloc / cfg_store_free / cfg_store_heap_free:
* 共享核心临时缓冲改走 FreeRTOS 堆(P0-1,MicroLIB C 堆仅 512B)
*/
/* 头文件包含区 */
#include <string.h>
#include "FreeRTOS.h"
#include "cfg_file_store.h"
#include "ff.h"
@@ -156,3 +160,37 @@ const char *cfg_store_tmp_path(void) {
const char *cfg_store_legacy_path(void) {
return s_path_legacy;
}
/*
* 函数功能:分配共享核心临时缓冲(FreeRTOS 堆)
* 入口参数:size - 字节数 size_t
* 返回值:缓冲指针(内容未清零);失败返回 NULL void *
* 限定条件:任务上下文调用(heap_4 内部临界区自护);释放必须用 cfg_store_free
* 函数说明:MCU 端 MicroLIB C 堆仅 512B(startup Heap_Size=0x200),共享核心的 KB 级
* 缓冲若走 C 库 malloc 必然返回 NULL,故统一由本接口取 FreeRTOS 堆(P0-1)
*/
void *cfg_store_alloc(size_t size) {
return pvPortMalloc(size);
}
/*
* 函数功能:释放 cfg_store_alloc 分配的临时缓冲
* 入口参数:p_buf - 缓冲指针(NULL 安全) void *
* 返回值:无
* 限定条件:p_buf 必须来自 cfg_store_alloc(禁止释放栈地址或 C 库指针)
*/
void cfg_store_free(void *p_buf) {
if (p_buf != NULL) {
vPortFree(p_buf);
}
}
/*
* 函数功能:FreeRTOS 堆当前空闲字节数(分配失败诊断)
* 入口参数:无
* 返回值:空闲字节数(未计入碎片影响) uint32_t
* 限定条件:无
*/
uint32_t cfg_store_heap_free(void) {
return (uint32_t)xPortGetFreeHeapSize();
}