# 静态最坏链回归的归因(同涨同一数值 = 共享帧,不是调用方)(自 SKILL.md 外置) > 本文由 mem-budget 的 SKILL.md「静态最坏链回归的归因(同涨同一数值 = 共享帧,不是调用方)」一节逐字外置而来(渐进展开:主文件只留索引与指针)。步骤号沿用原文,未重编。 - **多条任务链分毫不差同涨/同降同一个数值**(实测 default/net/iec104 三条 +80 B;断环后九条链各 −80 B) ⇒ 加深在这些任务**共用的被调帧 / 共享尾段**上,不在任何一个调用方。别逐个调用方翻, 也**别先猜"新增了大局部缓冲"**——实测猜错过一次(`con_ring_try` 只有 24 B 帧、没有数组)。 - 逐棵树逐帧比 frame size,不要只比总数: - `stack_report.py` 输出的「Frame-size ranking (own frame)」表 + 每任务最坏链文本,锁定**链尾公共段** (实测落在 `dbg_console_write_line → con_append → dbg_console_drain`,据此把账记到上一笔提交上); - 直接在 .htm 里找环:`grep -ac 'In Cycle' MDK-ARM/STM32F407-Demo/STM32F407-Demo.htm`(实测 17 处), 形态为 `Max Depth = 280 + In Cycle` 与 `Call Chain = Error_Handler => dbg_console_write_line (Cycle)`。 `+ In Cycle` 表示 armlink 把**环上所有帧**计入含该环的每一条任务链——**链接器幻影环**能在无人改栈配置时让全仓链齐涨。 - 实测样本(无人改栈配置、全仓链却齐涨的那种):taskEXIT_CRITICAL ⇒ vPortExitCritical ⇒ configASSERT ⇒ vApplicationAssertFailed ⇒ dbg_console_write_raw ⇒ 回到 console_log 内部 ⇒ 再进临界区; 它使 `vApplicationAssertFailed` 的 Max Depth 由 ~40 B 变 128 B + In Cycle,差 88 B ≈ 三条链同涨 80 B 的来源。 断环方向:内核临界区改 PRIMASK 保存/恢复(保存量放局部变量)→ 零调用帧、不成环; 断环的**图证**(该帧从「136 B + In Cycle」变成「8 B、不再 In Cycle」)比数字更有说服力。 - `Maximum Stack Usage = N bytes + Unknown(Cycles, Untraceable Function Pointers)` 里的 `+ Unknown(...)` 说明静态图对环与函数指针不可完全解析,静态数是估计值,别当精确值上报。 - 不采信任何口头结论:用**目标树的脚本 + `.venv` 解释器**自己复算;复算同样先按上节钉身份。 - 处置后的下一步:抬栈(`Src/freertos.c` 的 `USER CODE` 区,属 Ask-first 动作)或收紧共享缓冲 / 断环, **改前改后各一次** `stack_report.py` + `ram_report.py`,且"改后"那次必须落在一次新的 Linker run 上; 抬栈后跑 `gen_task_table.py` 同步任务表。