控制台改单写者发送:defaultTask唯一发串口其余任务写环形缓冲,杜绝日志交错与脏指针入UART;溢出钩子加指针窗口校验、崩溃上报改显式长度
This commit is contained in:
+56
-14
@@ -269,12 +269,21 @@ void StartDefaultTask(void *argument)
|
||||
/* 配置 poll 周期计数(每 4 次循环 = 2s 轮询一次,与引擎文档/模拟器一致) */
|
||||
uint32_t cfg_poll_cnt = 0u;
|
||||
|
||||
/* 注册控制台写者:本任务此后是串口唯一发送者(其余任务只写环形缓冲)。
|
||||
* 见 Src/usart.c "控制台单写者日志"——消除并发写造成的日志逐字符交错,
|
||||
* 并让脏指针无法再进入 HAL_UART_Transmit 的缓冲遍历。 */
|
||||
dbg_console_writer_attach();
|
||||
|
||||
for (;;) {
|
||||
/* 等待"保存网络配置"请求:有请求立即唤醒;无请求 500ms 后返回
|
||||
* (取代原 osDelay(500):循环节奏不变,保存响应零空转) */
|
||||
/* 等待"保存网络配置"或"控制台待发":任一即醒;无事件 500ms 后返回
|
||||
* (取代原 osDelay(500):循环节奏不变,保存/日志响应零空转) */
|
||||
if (sys_evtHandle != NULL) {
|
||||
(void)osEventFlagsWait(sys_evtHandle, SYS_EVT_CFG_SAVE, osFlagsWaitAny, 500u);
|
||||
(void)osEventFlagsWait(sys_evtHandle,
|
||||
SYS_EVT_CFG_SAVE | SYS_EVT_CONSOLE_TX,
|
||||
osFlagsWaitAny, 500u);
|
||||
}
|
||||
/* 控制台唯一发送点:把环形缓冲中的日志按块发出(无待发时立即返回) */
|
||||
dbg_console_drain();
|
||||
/* 执行待处理保存(配置引擎属主:写盘 + 成功后立即应用);无请求 = 空操作 */
|
||||
#if !defined(TEST_SUITE_STORAGE)
|
||||
net_cfg_save_run();
|
||||
@@ -633,38 +642,71 @@ static void default_task_net_cfg_save_notify(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 名称指针合法性校验(栈溢出/越界可能已破坏 TCB,指针不可信):
|
||||
* 只接受落在 Flash / 主 SRAM / CCM 映射范围内的指针;不校验就直接交给 UART,
|
||||
* 钩子自身也会以同样方式崩(2026-09-24 实测 HardFault:BFAR=0x10010000 恰为
|
||||
* CCM 末尾+1,PC 落在 HAL_UART_Transmit 的缓冲读取处)。
|
||||
*/
|
||||
static int hook_ptr_ok(const void *p)
|
||||
{
|
||||
uint32_t a = (uint32_t)p;
|
||||
uint32_t win = 32u; /* 将要读取的最大字节数(任务名 ≤ 32) */
|
||||
|
||||
if ((a >= 0x08000000u) && (a <= (0x08100000u - win))) {
|
||||
return 1; /* Flash(RO 区) */
|
||||
}
|
||||
if ((a >= 0x20000000u) && (a <= (0x20020000u - win))) {
|
||||
return 1; /* SRAM1 + SRAM2 */
|
||||
}
|
||||
if ((a >= 0x10000000u) && (a <= (0x10010000u - win))) {
|
||||
return 1; /* CCM(FreeRTOS 堆:TCB/栈所在) */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 栈溢出钩子(configCHECK_FOR_STACK_OVERFLOW=2,2026-09-20 存储套件死机事故后加):
|
||||
* 溢出 = 内核状态已不可信,禁止走 printf/内核对象,裸 UART 报任务名后复位。
|
||||
* 溢出 = 内核状态已不可信,禁止走 printf/内核对象/控制台锁,裸发固定文本后复位。
|
||||
* 2026-09-24 加固:任务名先经范围校验并拷入本地缓冲(不再把 TCB 指针交给 UART),
|
||||
* 指针不可信时打印占位文本——避免"上报崩溃的代码自己再崩一次"。
|
||||
*/
|
||||
void vApplicationStackOverflowHook(void *xTask, signed char *pcTaskName)
|
||||
{
|
||||
static const char msg_head[] = "\r\n[ERR] STACK OVERFLOW task=";
|
||||
static const char msg_bad[] = "(name unavailable)";
|
||||
uint16_t len = 0u;
|
||||
|
||||
(void)xTask;
|
||||
HAL_UART_Transmit(&huart1, (const uint8_t *)msg_head,
|
||||
(uint16_t)(sizeof(msg_head) - 1u), 0xFFFFu);
|
||||
if (pcTaskName != NULL) {
|
||||
uint16_t len = 0;
|
||||
while (len < 32u && pcTaskName[len] != '\0') {
|
||||
dbg_console_write_raw(msg_head, (unsigned)(sizeof(msg_head) - 1u));
|
||||
|
||||
if ((pcTaskName != NULL) && (hook_ptr_ok(pcTaskName) != 0)) {
|
||||
while ((len < 32u) && (pcTaskName[len] != '\0')) {
|
||||
len++;
|
||||
}
|
||||
HAL_UART_Transmit(&huart1, (const uint8_t *)pcTaskName, len, 0xFFFFu);
|
||||
}
|
||||
HAL_UART_Transmit(&huart1, (const uint8_t *)"\r\n", 2u, 0xFFFFu);
|
||||
if (len == 0u) {
|
||||
dbg_console_write_raw(msg_bad, (unsigned)(sizeof(msg_bad) - 1u));
|
||||
} else {
|
||||
char name[33]; /* 拷入本地缓冲:UART 永不接触 TCB 指针 */
|
||||
|
||||
memcpy(name, pcTaskName, (size_t)len);
|
||||
name[len] = '\0';
|
||||
dbg_console_write_raw(name, (unsigned)len);
|
||||
}
|
||||
dbg_console_write_raw("\r\n", 2u);
|
||||
HAL_Delay(200);
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
/*
|
||||
* 堆分配失败钩子:只告警不复位(NULL 由各调用点自行处理并上报自检)。
|
||||
* 同样走裸 UART——钩子可能在临界区内被调,printf/信号量不可用。
|
||||
* 同样走裸 UART 有界发送——钩子可能在临界区内被调,printf/信号量不可用。
|
||||
*/
|
||||
void vApplicationMallocFailedHook(void)
|
||||
{
|
||||
static const char msg[] = "\r\n[ERR] MALLOC FAILED (heap exhausted)\r\n";
|
||||
|
||||
HAL_UART_Transmit(&huart1, (const uint8_t *)msg,
|
||||
(uint16_t)(sizeof(msg) - 1u), 0xFFFFu);
|
||||
dbg_console_write_raw(msg, (unsigned)(sizeof(msg) - 1u));
|
||||
}
|
||||
/* USER CODE END Application */
|
||||
|
||||
Reference in New Issue
Block a user