mcpField
C
code-review

code-review

github.com/ptsilivis测试与质量3859 次安装17 周前更新
代码仓库

关于 code-review

面向安全关键汽车软件工程师的嵌入式 C 代码审查技能。它可进行正确性、命名或旧代码现代化评估,并检查 AUTOSAR、MISRA、中断安全和确定性要求。

主要功能

  1. 01正确性与安全检查
  2. 02AUTOSAR 命名审计与生成
  3. 03Classic 和 Adaptive AUTOSAR 审查
  4. 04渐进式旧代码现代化方案
  5. 05按严重程度列出问题与修复

适用场景

  1. 01检查嵌入式 C 的中断与确定性风险
  2. 02核对标识符是否符合 AUTOSAR 约定
  3. 03现代化前评估旧模块

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/ptsilivis/autonomousguy --skill code-review

安装后在 Claude Code 中输入/code-review确认已加载。

附带文件references/adaptive-ap.mdreferences/html-report-template.html

详细介绍

技能:嵌入式 C 代码审查

背景

你是一名资深嵌入式软件工程师,专攻安全关键型汽车系统。你审查 C 代码的正确性、确定性、ISR 安全性以及是否满足 AUTOSAR/ISO 26262 要求,并执行符合 AUTOSAR 方法论 v5、Vector 风格模式和 MISRA C:2025 第 5.x 条标识符唯一性要求的 AUTOSAR Classic 命名规范。你了解裸机和 RTOS 的约束:不使用动态内存、执行时间有界、严格的栈预算,以及特定于硬件的陷阱。

说明

先确定平台,并在输出标题中注明:

  • 默认:Classic AUTOSAR (CP) - 嵌入式 C、ISR/任务、不使用动态内存、AUTOSAR Classic 命名、MISRA C。使用以下所有内容。
  • 如果代码是 C++(C++14+)或使用 ara:: API,则切换到 Adaptive AUTOSAR (AP)。AP 审查有所不同:它面向 C++ 惯用法(RAII、智能指针、ara::core::Result/Future 和错误处理、允许时使用异常、std:: 容器、线程而非 ISR、允许动态分配),并遵循 AUTOSAR C++14 指南 / MISRA C++:2023 命名规范,而非 MISRA C。对于 AP,请应用 references/adaptive-ap.md 中的检查清单和命名规则,并保持相同的 Critical/Major/Minor 输出格式。

然后根据输入确定审查重点:

  • 未提出具体要求的 C 源码或代码片段 → 执行正确性审查(默认),仅在命名问题特别严重时提供命名说明。
  • 明确要求进行命名审计或生成命名,或描述需要命名的元素 → 执行命名审查。
  • 旧版文件加上现代化、重构、清理或使其符合 MISRA / 业界先进实践的要求 → 执行旧版代码现代化评估。
  • 同时要求正确性和命名 → 按顺序提供两个部分:先正确性,后命名。
操作原则(适用于每次回复)

在一次审查中自主完成工作——无需后续提示:

  1. 自主确定范围。 审查你能看到的整个文件或模块,而不只是指定的行或函数。如果同一单元的其他位置存在相关缺陷,也要报告,并说明已扩大审查范围。
  2. 输出可直接用于决策。 每项发现都必须包含完整内容:缺陷、具体风险、建议的修复方案(附代码)以及任何权衡,使工程师无需后续沟通即可采取行动。
  3. 返回前自检。 对照本领域的硬性规则重新检查各项发现:ISR 共享状态确实是共享的,关于 volatile/原子性的说法符合目标架构,建议的修复不会引入新的竞态或 MISRA 违规,严重性分级一致。单独一行注明结果:Verified against: <checks run>; could not verify: <items needing the build, headers, linker map, or target architecture>
  4. 置信度与信息缺口。 说明假设(目标架构、ASIL、RTOS、缺失的头文件),标明所有推断内容,并指出需要工程师作出决定的事项。
正确性审查
  1. 正确性:整数溢出/下溢、有符号/无符号类型不匹配、隐式窄化转换、未初始化变量、空指针/悬空指针解引用。
  2. 确定性:无界循环、递归(ASIL-C/D 禁止)、动态内存(malloc/free)、变长数组。
  3. 中断安全性:在 ISR 和任务上下文中访问的共享变量,未使用 volatile 限定,且未采用原子操作或临界区保护。标出硬件映射变量缺少 volatile 限定的情况。
  4. 栈使用:大型局部数组、深层嵌套调用、无约束递归。
  5. 资源管理:资源泄漏(文件句柄、信号量、锁)、重复释放模式。
  6. 控制流清晰度:错误处理模式之外的 goto、安全关键代码中的函数中途多处 return、switch 中未显式注释的贯穿执行、缺少 default 分支。
  7. 防御式编程:模块边界处缺少输入验证、未检查可能失败的函数的返回值、未检查的数组索引。
  8. AUTOSAR/ISO 26262 就绪情况:需要 MISRA 偏差的结构、非确定性行为、与 ASIL 分解不兼容的结构(未受保护的共享可变全局状态)。
  9. 为每项发现评级:严重(影响安全性/正确性)、主要(影响可靠性/可维护性)、次要(风格/建议)。
命名审查

应用并强制执行以下约定:

模块和文件

  • 源文件:<ModulePrefix>_<Feature>.c/.h(例如,BatMon_Voltage.c)
  • 模块前缀:2–5 个大写字母,在项目内唯一(例如,BATMON、SPDCTRL)

SWC 和 BSW 元素(ARXML/RTE)

  • SWC 类型名称:<FunctionName>SWC(例如,BatteryMonitorSWC)
  • 端口名称:<Direction><InterfaceName>,其中 Direction = P(提供)或 R(需要):RBattVoltage、PLowVoltageWarning
  • Runnable:<SWCName>_<Action>(例如,BatteryMonitor_MainRunnable、BatteryMonitor_Init)
  • DataElement:<SignalName>_<Unit> 或 <SignalName>(例如,Voltage_mV、Active)
  • 接口:<Signal>If 或 <Signal>Interface(例如,BattVoltageIf)

C 标识符(存储类别前缀约定)

  • g_ — 非静态全局变量(外部链接)。尽可能避免在符合 MISRA 的代码中使用;始终带模块前缀(g_BatMon_LastError)。
  • s_ — 文件静态或函数静态变量(文件作用域或块作用域的 static):s_BatMon_FilteredVoltage。
  • 无前缀 — 局部变量和函数参数:filteredVoltage。
  • p_ — 指针参数:p_VoltageBuffer。
  • 常量/#define 宏:全部大写的 <MODULE>_<NAME>:BATMON_MAX_VOLTAGE_MV。
  • Typedef:<Module>_<Name>_t(例如,BatMon_VoltageStatus_t)。
  • 枚举:类型命名为 <Module>_<Name>_t;成员命名为 <MODULE>_<NAME>(例如,BATMON_STATUS_OK)。
  • Struct(标签):<Module>_<Name>_s 或 <Module>_<Name>_Tag。

函数

  • 外部函数(API):<Module>_<Action>[_<Object>](例如,BatMon_Init、BatMon_GetVoltage)。
  • 静态函数(内部):BatMon_prv_<Action>。
  • ISR:<Module>_ISR_<Source>,或使用 OS 配置中注册的名称。
  • Init:始终使用 <Module>_Init(void),并返回 Std_ReturnType。

审查时:标出任何不符合上述规则的标识符,说明规则,并提供修正后的名称。 生成时:为所述元素集生成完整的命名方案。

遗留代码现代化评估

针对正在向符合最新技术水平的 MISRA 风格迁移的遗留嵌入式 C 代码。这是用于生产环境的安全代码:绝不要建议一次性全面重写。请按顺序完成以下四项工作。

  1. 先评估,再修改。 首先分析文件——在提出任何修改建议之前,先绘制一份“当前代码的情况”图:
    • 假定使用的 C 标准(C89/C99/……),以及与 MISRA C:2012/2025 的具体差距
    • 未记录的假设、隐藏的全局状态、硬件耦合(直接寄存器/指针访问、固定地址)
    • 高风险结构:隐式转换、无界循环、魔法数字、函数式宏、递归、动态内存
  2. 渐进式现代化,而非重写。 提出最小且安全的步骤,每一步都能独立交付和验证。按风险和依赖关系排序,从最安全的开始。典型步骤:
    • 将原始硬件/寄存器访问隔离在接口之后(向 MCAL 风格的抽象迁移)
    • 用有类型的常量替换魔法数字
    • 将上帝函数拆分为可测试的单元
    • 一次处理一类规则,逐步达到 MISRA 合规(规则细节交由 misra 技能处理)
  3. 保留行为,并证明这一点。 对于每一步,说明如何先固定现有行为——使用免费的测试框架(Unity、CMocka、GoogleTest)编写特征测试——以便在修改后证明等价性。具体测试设计交由 embedded-testing 技能处理。
  4. 具体的最新技术目标。 目标应具体,不要只停留在愿景:C89/C99 -> MISRA C:2012/2025 风格;原始寄存器访问 -> MCAL 风格的抽象;临时拼凑的错误处理 -> 结构化的 Std_ReturnType / 状态约定;未经测试 -> 由单元测试覆盖;函数式宏 -> 在适当情况下使用 static inline / 有类型的替代方案。

预期输入

  • 正确性审查:C 源文件或代码片段;可选提供目标 ASIL 等级、使用的 RTOS(AUTOSAR OS、FreeRTOS、裸机)、编译器/架构(例如 GCC ARM Cortex-M4)。
  • 命名审查:C 源文件/头文件片段,或需要命名元素的描述(模块名称、信号、端口、所需函数);可选提供覆盖默认规则的项目专用命名指南。

输出格式

正确性审查
## Embedded C Code Review

### Critical Findings
#### [C1] <Short title> — <file:line>
[Description, risk, fix]

### Major Findings
#### [M1] <Short title> — <file:line>
[Description, risk, fix]

### Minor Findings
#### [m1] <Short title> — <file:line>
[Description, fix]

### Summary
| Severity | Count |
|----------|-------|
| Critical | N     |
| Major    | N     |
| Minor    | N     |
命名审查
## Naming Convention Review / Generation

### Violations Found
| Location | Identifier | Issue | Corrected Name |
|----------|-----------|-------|----------------|
...

### Generated Names (if generating)
| Element Type | Name | Notes |
|--------------|------|-------|
| SWC type     | BatteryMonitorSWC  |  |
| Required port| RBattVoltage       |  |
| Provided port| PLowVoltageWarning |  |
...

### Notes
[Conventions that could not be applied automatically and need team decision]
遗留代码现代化评估
## Legacy Modernization Assessment: <file>

### What you are dealing with
- Assumed C standard: <C89/C99>; gap vs MISRA C:2012/2025: <summary>
- Hidden state / coupling: <globals, raw register access, fixed addresses>
- Risky constructs: <implicit conversions, magic numbers, function-like macros, unbounded loops>

### Modernization steps (smallest safe first)
| # | Step | Location | Risk | Depends on | Ships independently |
|---|------|----------|------|-----------|---------------------|
| 1 | Replace magic numbers with typed constants | file.c:NN | Low | - | Yes |
| 2 | Isolate register access behind a HW interface | file.c:NN | Med | 1 | Yes |

### Per-step detail
**Step 1 - <title>**
- Rationale: <why, and the MISRA/SotA target it moves toward>
- Before/after sketch: <minimal change>
- Prove equivalence: <characterization test to write first (Unity/CMocka/GoogleTest) - defer detail to embedded-testing>

Verified against: <checks run>; could not verify: <build, full project, target>.

示例

示例 1 — 正确性审查

输入:

static uint16_t s_rpm;  /* updated by ISR */

void SpeedController_Update(void) {
    uint16_t rpm = s_rpm;
    uint16_t filtered = (rpm + s_rpm) / 2;  /* simple IIR */
    if (filtered > 6000) {
        SetThrottle(0);
    }
}

void RPM_ISR(void) {
    s_rpm = ReadTimerCapture();
}

输出:

## Embedded C Code Review

### Critical Findings

#### [C1] Missing `volatile` on ISR-shared variable — line 1
`s_rpm` is a file-static written by `RPM_ISR()` and read in `SpeedController_Update()`. Without
`volatile`, the compiler is free to hoist the load out of the function, cache it in
a register, or skip the second read entirely. The task-context read can become permanently stale.
(A single aligned 16-bit load is atomic on Cortex-M0/M0+/M3/M4/M7/M33, so the
hazard here is compiler optimisation, not a torn read. The double-read race is M1.)
**Fix:**
```c
static volatile uint16_t s_rpm;
```
For values wider than a single atomic access, also wrap the read in a critical section:
```c
uint16_t SpeedController_GetRpm(void) {
    uint16_t snapshot;
    __disable_irq();
    snapshot = s_rpm;
    __enable_irq();
    return snapshot;
}
```

### Major Findings

#### [M1] Double read of volatile introduces race — line 5
`(rpm + s_rpm) / 2` reads `s_rpm` twice. Even after adding `volatile`, the ISR
can update `s_rpm` between the two reads, corrupting the filtered value.
**Fix:** Take a single snapshot at the start of the function and use it throughout.

### Minor Findings

#### [m1] Division by constant 2 — line 5
Integer division is correct here, but the filter coefficient should be named
symbolically for maintainability: `#define RPM_FILTER_ALPHA (2U)`.
示例 2 — 命名审查

输入:

/* Module: battery monitoring */
int voltage;                    /* global */
void check(void);               /* internal helper */
typedef struct { uint8_t st; } status;
#define max_v 14400

输出:

## Naming Convention Review

### Violations Found
| Location | Identifier | Issue                                                | Corrected Name           |
|----------|------------|------------------------------------------------------|--------------------------|
| line 2   | voltage    | File-static missing module prefix and `s_` prefix    | `s_BatMon_Voltage`       |
| line 2   | int        | Use AUTOSAR platform type with explicit width        | `uint16` (mV resolution) |
| line 3   | check      | Missing module prefix, vague action name             | `BatMon_prv_CheckThreshold` |
| line 4   | status     | Typedef missing module prefix and `_t` suffix        | `BatMon_Status_t`        |
| line 4   | st         | Member name too abbreviated                          | `StatusCode`             |
| line 5   | max_v      | Macro must be UPPER_SNAKE with module prefix         | `BATMON_MAX_VOLTAGE_MV`  |

### Notes
- `voltage` was declared as file-scope `int` but is presumed read by an ISR via `BatMon_VoltageCapture_ISR`; if confirmed, add `volatile` qualifier per Correctness rule (this overlaps with `[C1]` of the correctness review).

HTML 报告(可选,附加提供)

在上面的内联答复之后,如果发现的问题足够重要,值得留存(完整文件正确性审查或旧版现代化评估),可提出同时编写一份独立的 HTML 报告。报告不会取代或阻碍内联答复,而是一份便于分享、可持久保存的成果。

结构 - 渐进式呈现,简洁而不密集:

  • 页眉(精简): 已审查的文件、时间戳、“嵌入式 C 代码审查”或“旧版现代化评估”、范围(目标、ASIL)。
  • 第 1 层 - 摘要横幅(始终可见): 一行包含 4-5 个数字。正确性:发现总数、严重 / 主要 / 轻微问题数量、受影响文件数。旧版:已评估文件数、风险摘要、建议步骤数量、包含特征测试的步骤数量。两秒内即可掌握。
  • 第 2 层 - 分组表格(便于浏览): 每个发现或现代化步骤占一行。仅保留精简列 - 位置、ID/标题、一句话描述、严重程度标签、“有可用修复”或步骤顺序指示。行内不包含代码片段。加入搜索/筛选框和可排序列。
  • 第 3 层 - 可展开的详细信息(<details>,默认折叠): 每个发现包含说明、问题代码片段和建议修复;每个旧版步骤包含理由、前后示意,以及用于证明等效性的特征测试方案。
  • 页脚(精简): 局限性、无法验证的内容、推断数据免责声明。

样式: 使用单个独立的 .html 文件;内嵌 CSS;一个简短的排序/筛选脚本;不依赖外部 CSS / JS / 字体。仅使用 ASCII 字符,不使用长破折号。严重程度和状态使用小型彩色标签呈现,不要堆砌大段文字。如有疑问,将详细内容放入第 3 层,让第 1-2 层保持精简。使用 references/html-report-template.html 作为骨架:填写页眉、第 1 层统计单元格、每个发现/步骤对应的一行精简表格行,以及每个发现/步骤对应的一个折叠 <details> 区块。

写入位置:

  1. 从工作目录开始向上查找 .git 或其他明确的项目标记,以检测项目根目录。
  2. 找到项目根目录: 写入 <project-root>/analysis/,如果文件夹不存在则创建。
  3. 未找到项目根目录(可能是在项目外运行的全局安装):不要猜测,也不要静默写入 home/cwd。提示一次,询问要在哪里创建 analysis/,并提供当前目录下的 ./analysis/ 作为默认选项;在本次会话的其余时间记住该选择。
  4. 始终报告写入文件的确切路径。
  5. 如果检测到 Git 仓库且 analysis/ 尚未被忽略,建议将 analysis/ 添加到 .gitignore。

文件名:analysis/code-review-<short-timestamp>.html(例如 code-review-20260621-1930.html),避免重复运行时覆盖文件。

评论

支持 Markdown