关于 ln-628-concurrency-correctness-auditor
用于代码库审计的专用 Skill,检查异步竞态、线程安全、死锁、阻塞 I/O、资源争用及跨进程竞争。采用候选扫描后结合上下文核验,并输出问题、建议和合规分数。
主要功能
- 01检测异步竞态与线程安全问题
- 02识别 TOCTOU 风险和死锁
- 03发现异步上下文中的阻塞 I/O
- 04检查资源争用与跨进程竞争
- 05计算合规分数并生成报告
适用场景
- 01审查共享状态在并发访问下的风险
- 02排查异步处理中的阻塞调用
- 03评估文件或操作系统资源的并发访问
MCP 相关
可优先使用 hex-line 读取和搜索代码;当数据流或调用路径分析有助于并发问题判断时使用 hex-graph。MCP 不可用时改用内置工具。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ levnikolaevich/ claude-code-skills --skill ln-628-concurrency-correctness-auditor安装后在 Claude Code 中输入/ln-628-concurrency-correctness-auditor确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/audit_output_schema.mdaudit_scoring.mdaudit_summary_contract.mdaudit_worker_core_contract.mdmcp_integration_patterns.mdmcp_tool_preferences.mdtwo_layer_detection.mdreferences/templates/audit_worker_report_template.md详细介绍
路径: 文件路径(
references/、../ln-*)均相对于此技能目录。
并发正确性审计器(L3 Worker)
类型: L3 Worker
专门审计并发正确性、异步风险和跨进程资源访问的 Worker。
目的与范围
- 审计并发(类别 11:高优先级)
- 7 项检查:异步竞争、线程安全、TOCTOU、死锁、阻塞式 I/O、资源争用、跨进程竞争
- 两层检测:grep 查找候选项,Agent 根据上下文进行判断
- 输出
FIX_RACE、FIX_DEADLOCK或CONTROL_ASYNC_SIDE_EFFECT - 计算合规评分(X/10)
输入
必须读取: 加载 references/audit_worker_core_contract.md 和 references/mcp_tool_preferences.md。
工具策略:你可以作为独立子 Agent 运行,此时宿主的 AGENTS.md 不在适用范围内,因此读取、搜索和编辑文件时默认优先使用 hex-line MCP。仅当 MCP 行为不明确时,才加载 references/mcp_integration_patterns.md。
接收包含以下内容的 contextStore:tech_stack、best_practices、codebase_root、output_dir。
如果数据流或调用路径分析能显著改善并发问题发现结果,请优先使用 hex-graph。如果 hex-line 可用,读取本地代码时请优先使用 hex-line。如果 MCP 不可用、不受支持或未编入索引,请继续使用内置的 Read/Grep/Glob/Bash,并在报告中说明回退情况。
工作流
检测策略:使用两层检测(扫描候选项,然后验证上下文);仅当验证方法存在歧义时,才加载 references/two_layer_detection.md。
- 解析上下文——从 contextStore 中提取 tech_stack、语言和 output_dir
- 逐项检查(1-7):
- 第 1 层: 使用 Grep/Glob 扫描查找候选项
- 第 2 层: 阅读每个候选项周围 20-50 行。应用对应检查项的关键问题。分类为:已确认/误报/需要上下文
- 收集已确认的问题,包括严重程度、位置、工作量和建议
- 根据
references/audit_scoring.md计算评分 - 编写报告——在内存中构建报告,然后写入
{output_dir}/ln-628--global.md(单次原子 Write) - 返回摘要
审计规则
统一严重程度升级规则: 对于所有检查项,如果问题影响支付、身份验证或金融代码,则无论其他因素如何,均升级为严重(CRITICAL)。
1. 异步/事件循环竞争(CWE-362)
说明: 单线程异步代码中的共享状态跨越 await/yield 边界时遭到破坏。
第 1 层——Grep 模式:
| 语言 | 模式 | Grep |
|---|---|---|
| JS/TS | 跨 await 的读取-修改-写入 | \w+\s*[+\-*/]?=\s*.*await(例如:result += await something) |
| JS/TS | 检查后初始化竞争 | 同一代码块内先出现 if\s*\(!?\w+\),随后出现 \w+\s*=\s*await |
| Python | 跨 await 的读取-修改-写入 | async def 内的 \w+\s*[+\-*/]?=\s*await |
| Python | 异步代码中的模块级共享状态 | 模块级 \w+\s*=,且在 async def 内修改 |
| All | 未加锁的共享缓存 | 异步函数中存在 `.set( |
第 2 层——关键问题:
- 该变量是共享的(模块/全局作用域),还是局部变量?
- 两个异步任务能否在此 await 处交错执行?
- 是否有锁/互斥锁/信号量保护此访问?
严重程度: 严重(CRITICAL)(支付/身份验证)| 高(面向用户)| 中(后台)
安全模式排除项: 局部变量、const 声明、单次使用 await(不存在交错执行的可能)。
工作量: M
2. 线程/协程安全(CWE-366)
内容: 多个线程/协程在未同步的情况下访问共享可变状态。
第 1 层 -- Grep 模式:
| 语言 | 模式 | Grep |
|---|---|---|
| Go | 未使用互斥锁的映射访问 | 结构体中出现 map\[.*\].*=,但没有 sync.Mutex 或 sync.RWMutex |
| Go | 被协程捕获的变量 | go func + 被修改的外部作用域变量 |
| Python | 在线程中修改全局变量 | 函数中出现 global\s+\w+,且同一文件中出现 threading.Thread |
| Java | 多个线程共享 HashMap | 同一类中出现 HashMap + Thread|Executor|Runnable,但没有 synchronized|ConcurrentHashMap |
| Rust | 多线程上下文中的 Rc | 同一文件中出现 Rc<RefCell + thread::spawn|tokio::spawn |
| Node.js | Worker Threads 共享状态 | 出现 workerData|SharedArrayBuffer|parentPort,且存在未使用 Atomics 的可变访问 |
第 2 层 -- 关键问题:
- 这个结构体/对象实际上会在线程间共享吗?(单线程代码 -> 误报)
- 互斥锁/锁是在嵌入的结构体中,还是在导入的模块中?(grep 可能会漏掉)
go func是按值捕获(安全)还是按引用捕获(不安全)?
严重程度: 严重(支付/身份验证) | 高(可能导致数据损坏) | 中(内部)
安全模式排除项: 在 goroutine 启动前,于 init() 或 main() 中使用的 Go 映射。Rust Arc<Mutex<T>>(本身已安全)。Java Collections.synchronizedMap()。
工作量: M
3. TOCTOU -- 检查与使用之间的竞态(CWE-367)
内容: 检查资源状态后再使用,但状态可能在检查与使用之间发生变化。
第 1 层 -- Grep 模式:
| 语言 | 检查 | 使用 | Grep |
|---|---|---|---|
| Python | os.path.exists() | open() | 同一变量上的 os\.path\.exists\( 与 open\( 相邻出现 |
| Python | os.access() | os.open() | os\.access\( 与 os\.open\(|open\( 相邻出现 |
| Node.js | fs.existsSync() | fs.readFileSync() | existsSync\( 与 readFileSync\(|readFile\( 相邻出现 |
| Node.js | fs.accessSync() | fs.openSync() | accessSync\( 与 openSync\( 相邻出现 |
| Go | os.Stat() | os.Open() | os\.Stat\( 与 os\.Open\(|os\.Create\( 相邻出现 |
| Java | .exists() | new FileInputStream | \.exists\(\) 与 new File|FileInputStream|FileOutputStream 相邻出现 |
第 2 层 -- 关键问题:
- 检查结果用于控制流(易受攻击),还是仅用于日志记录(安全)?
- 检查与使用的序列周围是否有锁/重试?
- 文件是否位于由应用控制的临时目录中(风险较低)?
- 攻击者能否替换该文件(符号链接攻击)?
严重程度: 严重(安全敏感:权限、身份验证令牌、配置) | 高(面向用户的文件操作) | 中(内部/后台)
安全模式排除项: 在带重试的 try/catch 中进行检查。检查仅用于日志/指标。检查与使用由文件锁保护。
工作量: S-M(将先检查再使用替换为直接使用并处理错误)
4. 死锁风险(CWE-833)
含义: 以不一致的顺序获取锁,或在持有锁时执行阻塞操作。
第 1 层 -- Grep 模式:
| 语言 | 模式 | Grep |
|---|---|---|
| Python | 嵌套锁 | with\s+\w+_lock:(多行:嵌套使用两个不同的锁) |
| Python | 循环中的锁 | for.*:,且循环体内有 \.acquire\(\) |
| Python | 锁 + 外部调用 | \.acquire\(\) 后、释放锁前出现 await|requests\.|urllib |
| Go | 未使用 defer 解锁 | \.Lock\(\) 后的下一行没有 defer.*\.Unlock\(\) |
| Go | 嵌套锁 | 同一函数中有两个 \.Lock\(\) 调用,且中间没有 \.Unlock\(\) |
| Java | 嵌套 synchronized | synchronized\s*\((多行:嵌套块使用不同的监视器) |
| JS | 异步互斥锁嵌套 | await\s+\w+\.acquire\(\)(同一函数中使用两个不同的互斥锁) |
第 2 层 -- 关键问题:
- 这是同一个锁(可重入 = 安全),还是不同的锁(存在死锁风险)?
- 所有调用点的锁顺序是否一致?
- 锁内的外部调用是否设置了超时?
严重程度: 严重(支付/身份验证) | 高(存在应用卡死风险)
安全模式排除项: 可重入锁(同一个锁获取两次)。设置了显式超时的锁(asyncio.wait_for、tryLock)。
工作量: L(重新设计锁的顺序)
5. 异步上下文中的阻塞 I/O(CWE-400)
含义: 在异步函数或事件循环处理程序中调用同步阻塞操作。
第 1 层 -- Grep 模式:
| 语言 | 阻塞调用 | Grep | 替代方案 |
|---|---|---|---|
| Python | async def 中的 time.sleep | async def 中的 time\.sleep | await asyncio.sleep |
| Python | async def 中的 requests.* | async def 中的 requests\.(get|post|put|delete) | httpx 或 aiohttp |
| Python | async def 中的 open() | async def 中的 open\( | aiofiles.open |
| Node.js | async 中的 fs.readFileSync | fs\.readFileSync|fs\.writeFileSync|fs\.mkdirSync | fs.promises.* |
| Node.js | async 中的 execSync | 异步处理程序中的 execSync|spawnSync | 使用 promises 的 exec |
| Node.js | async 中的同步加密 | crypto\.pbkdf2Sync|crypto\.scryptSync | crypto.pbkdf2(回调) |
第 2 层 -- 关键问题:
- 这是热路径(API 处理程序)还是冷路径(启动脚本)?
- 阻塞时长是否显著(>100ms)?
- 是否有合理原因(例如,启动时同步读取小型配置文件)?
严重程度: 高(阻塞事件循环/异步上下文) | 中(轻微阻塞 <100ms)
安全模式排除项: 在 if __name__ == "__main__" 中调用阻塞操作(启动时)。初始化时加载配置的 readFileSync。处理小型输入的同步加密。
工作量: S-M(替换为异步替代方案)
6. 资源争用(CWE-362)
含义: 多个并发访问者在没有协调的情况下争用同一资源。
第 1 层 -- Grep 模式:
| 模式 | 风险 | Grep |
|---|---|---|
| 未同步的共享内存 | 数据损坏 | SharedArrayBuffer|SharedMemory|shm_open|mmap 附近没有 Atomics|Mutex|Lock |
| 未协调的 IPC | 消息顺序 | 并发循环中的 process\.send|parentPort\.postMessage |
| 并发追加文件 | 写入交错 | 并行任务将多个 appendFile|fs\.write 写入同一路径 |
第 2 层 -- 关键问题:
- 多个写入者是否真的并发?(顺序执行 = 安全)
- 是否有操作系统级的原子性保证?(例如,小型写入使用
O_APPEND) - 顺序是否会影响正确性?
严重程度: 高(数据损坏) | 中(顺序问题)
安全模式排除项: 单一写入者模式。操作系统保证的原子操作(小型管道写入、O_APPEND)。具有顺序保证的消息队列。
工作量: M
7. 跨进程与不可见副作用(CWE-362、CWE-421)
内容: 多个进程,或进程与操作系统同时访问同一独占资源;也包括对共享操作系统资源产生不明显副作用的操作。
第一层——查找入口:
| 模式 | 风险 | 查找 |
|---|---|---|
| 剪贴板双重访问 | 同一流程中使用 OSC 52 和原生剪贴板 | 在同一文件中查找 osc52|\\x1b\\]52 和 clipboard|SetClipboardData|pbcopy|xclip |
| 子进程 + 共享文件 | 父进程和子进程写入同一文件 | 同一路径上的 spawn|exec|Popen + writeFile|open.*"w" |
| 操作系统独占资源 | Win32 剪贴板、串行端口、命名管道 | OpenClipboard|serial\.Serial|CreateNamedPipe|mkfifo |
| 终端转义序列 | stdout 触发终端操作系统访问 | \\x1b\\]|\\033\\]|writeOsc|xterm |
| 外部剪贴板工具 | 通过生成的进程访问剪贴板 | pbcopy|xclip|xsel|clip\.exe |
第二层——这项检查比其他检查更依赖推理:
-
建立资源清单:
资源 是否独占? 访问方 1 访问方 2 是否有同步? -
追踪时间线:
t=0ms operation_A() -> resource_X accessed t=?ms side_effect -> resource_X accessed by external process t=?ms operation_B() -> resource_X accessed again -> CONFLICT? -
关键问题:
- 其他进程(终端、操作系统、子进程)能否同时访问此资源?
- 此操作是否会对共享操作系统资源产生不可见的副作用?
- 外部进程比预期更慢或更快时会发生什么?
- 用户快速连续触发此操作两次时会发生什么?
严重程度: 严重(两个访问方访问独占操作系统资源且没有同步)| 高(子进程 + 共享文件且没有锁)| 高(通过推理发现不可见副作用)
安全模式排除项: 只有一个访问方。存在重试/退避模式。操作之间通过明确的延迟/等待进行排序。
工作量: M-L(可能需要移除冗余的访问路径)
评分算法
必须阅读: 加载 references/audit_scoring.md。
输出格式
必须阅读: 加载 references/templates/audit_worker_report_template.md。
按照 references/audit_summary_contract.md 编写 JSON 摘要。在托管模式下,调用方会传入 runId 和 summaryArtifactPath;在独立模式下,工作器会按照共享契约生成自己的运行专属产物路径。
将报告写入 {output_dir}/ln-628--global.md,其中 category: "Concurrency",并包含以下检查项:async_races、thread_safety、toctou、deadlock_potential、blocking_io、resource_contention、cross_process_races。
按照 references/audit_summary_contract.md 返回摘要。
当 summaryArtifactPath 不存在时,将独立模式的运行时摘要写入 .hex-skills/runtime-artifacts/runs/{run_id}/evaluation-worker/{worker}--{identifier}.json,也可以选择在结构化输出中回显相同的摘要。
Report written: .hex-skills/runtime-artifacts/runs/{run_id}/audit-report/ln-628--global.md
Score: X.X/10 | Issues: N (C:N H:N M:N L:N)
关键规则
应用已加载的 references/audit_worker_core_contract.md。
- 不要自动修复: 仅报告问题——并发问题的修复需要人工仔细审查
- 两层检测: 第一层查找后,始终应用第二层推理。切勿脱离上下文分析而直接报告原始查找结果
- 语言感知检测: 根据每项检查使用特定语言的模式
- 统一的严重级别升级: 支付/身份验证/金融代码中的任何问题均为严重
- 合理评估工作量: S = <1 小时,M = 1-4 小时,L = >4 小时
- 排除项: 跳过测试文件、单线程 CLI 工具和生成的代码
- 独特角度: 仅审计并发正确性。不要审计生命周期就绪情况、层所有权或本地代码风格。
- 必须采取行动: 每项发现都使用
FIX_RACE、FIX_DEADLOCK或CONTROL_ASYNC_SIDE_EFFECT。
完成定义
应用已加载的 references/audit_worker_core_contract.md。
- 已解析 contextStore(语言、并发模型、output_dir)
- 已完成全部 7 项检查,并采用双层检测:
- 异步竞态、线程安全、TOCTOU、死锁风险、阻塞式 I/O、资源竞争、跨进程竞态
- 已对每个候选项应用第二层推理(已确认 / 误报 / 需要上下文)
- 已收集发现项,包含严重性、位置、工作量、操作和建议
- 已根据
references/audit_scoring.md计算分数 - 已将报告写入
{output_dir}/ln-628--global.md(通过一次原子 Write 调用) - 已根据合同编写摘要
参考文件
- 双层检测方法:
references/two_layer_detection.md - 审计输出架构:
references/audit_output_schema.md
版本: 4.0.0 最后更新: 2026-03-04