修复了一个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");
}