mcpField
D
dotnet-inspect-correctness

dotnet-inspect-correctness

github.com/richlander测试与质量159415 次安装今天更新
代码仓库

关于 dotnet-inspect-correctness

这项技能指导使用 dotnet-inspect 检查 .NET 方法的异常行为与不安全操作,并强调依据证据评估,不能把未发现结果当作安全证明。

主要功能

  1. 01检查异常区域与调用图
  2. 02定位方法体中的不安全操作
  3. 03关联不同包版本的安全发现
  4. 04使用 jq 组合分类证据
  5. 05记录覆盖范围与未验证事项

适用场景

  1. 01审查方法的异常处理
  2. 02调查不安全内存操作
  3. 03结合不安全代码评估资源所有权
  4. 04按 .NET 不安全代码指南整理证据

安装

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

$npx skills add https://github.com/richlander/dotnet-inspect --skill dotnet-inspect-correctness

安装后在 Claude Code 中输入/dotnet-inspect-correctness确认已加载。

详细介绍

dotnet-inspect:正确性与安全性

使用此技能判断代码是否可靠且可安全调用:它可能引发什么异常、如何处理错误,以及在哪些地方会脱离安全的托管执行。此分析针对单个版本;若要了解这些信号在不同版本之间如何变化,请使用 compatibility 技能。

dnx dotnet-inspect -y -- <command>

它可能引发什么异常?(异常范围)

没有专门的“Exceptions”部分;异常行为通过方法体分析得出。Exception Regions 会显示精确的 catch/filter/finally 布局;图字段和隐藏事实则会概述相关行为:

dnx dotnet-inspect -y -- member Type Method:1 -S "Exception Regions"
dnx dotnet-inspect -y -- member Type Method:1 -S "Call Graph" --fields "Throws,ThrowSites,ExceptionTypes,ConstructedExceptions,Catch,Finally"
dnx dotnet-inspect -y -- member Type Method:1 -S "Call Graph" --fields "Throws,Catch,Finally"
dnx dotnet-inspect -y -- member Type Method:1 -S Facts --tsv

Throws/ThrowSites 统计抛出点;ExceptionTypes/ConstructedExceptions 列出异常类型;Catch/Finally 显示处理方式。Exception Regions 保留 IL 范围和捕获的类型。-S Facts(成员、单个方法)会列出方法体中的隐藏事实,并支持 --tsv。

它在内存方面安全吗?(不安全操作)

dnx dotnet-inspect -y -- member Type Method:1 --library MyLib.dll -S "Unsafe Operations,IL"

-S "Unsafe Operations" 会显示单个方法体中的不安全操作,并提供 IL 证据。若要了解整个库的安全范围(不安全成员、P/Invoke 方法)以及来源/供应链信号,请参阅 signals 技能。

对于某次崩溃或分析器坐标,使用 library coordinate 0x06000001+0x5 --library Foo.dll 获取默认的源位置、成员、指令、异常、调用点和返回地址上下文。安全证据需显式启用:library coordinate 0x06000001+0x5 --library Foo.dll -S "Context: Safety"。

若要确认某个明确的不安全操作是否出现在相邻版本边界,先关联由调用方选择的程序包单元格:

dnx dotnet-inspect -y -- diff --history --package [email protected] \
  -t MyType -m Method \
  --finding analysis.unsafety --at first --at last

对于稀疏探测,请重复使用 --at;对于有明确边界的密集遍历,请使用 --at all。跨越版本间隔的 Added 行可定位候选边界,但不能证明操作确切在哪个版本引入。请确认相邻版本对:

dnx dotnet-inspect -y -- diff --package [email protected] \
  -t MyType -m Method \
  --finding analysis.unsafety

PairFinding.Added 是引入操作的证据。Present 和 Removed 用于区分持续存在与消失;此命令仅比较提供的两个端点。

根据 .NET 指南审查不安全代码与所有权

将 .NET 不安全代码最佳实践指南 作为策略依据。其 源文档 目前将审查内容分为 26 个编号主题。

dotnet-inspect 提供编译后的证据,而不是包罗万象的合规性结论。获取可复用的 JSONL 行集,使用 Agent 和 jq 按每个问题筛选并联接这些行,然后仅对影响重大的 Members 进行深入检查。同一批行也能回答其他安全问题,无需新增聚合命令。

获取可复用的行集

将每一类行分别保存,以便清楚呈现其标识、结构和完成状态。记录每条命令的状态和诊断信息:聚焦部分为空,可能是非零结果,并非成功的空清查。

capture()
{
  output="$1"
  shift
  status=0
  "$@" > "$output" 2> "$output.stderr" || status=$?
  printf '%s\t%s\n' "$output" "$status" >> inspection-status.tsv
}

: > inspection-status.tsv
capture unsafe-members.jsonl \
  dnx dotnet-inspect -y -- library MyLib.dll \
    -S "Unsafe Members" --jsonl
capture pinvoke-methods.jsonl \
  dnx dotnet-inspect -y -- library MyLib.dll \
    -S "P/Invoke Methods" --jsonl
capture custom-attributes.jsonl \
  dnx dotnet-inspect -y -- library MyLib.dll \
    -S "Custom Attributes" --jsonl
capture references.jsonl \
  dnx dotnet-inspect -y -- library MyLib.dll \
    -S References --jsonl
capture signals.json \
  dnx dotnet-inspect -y -- library MyLib.dll \
    -S Signals --json

库级 Custom Attributes 涵盖经过筛选的程序集级和模块级特性。它不会发现 Type、字段或方法上的特性,也无法证明 SkipLocalsInit 的覆盖情况。请保留这一范围:只有在其他行或源代码证据选定 Type 或 Member 后,才使用精确目标的特性;并将整个库的特性发现情况报告为 unverified。

所有权与不安全代码相互交织。池化缓冲区可能没有指针操作码,却仍会因返回后使用、缺少清理或所有权转移而出错。请通过同一封装器,在获取不安全证据的同时获取 Resource Triage:

capture resource-triage.jsonl \
  dnx dotnet-inspect -y -- library MyLib.dll \
    -S "Resource Triage" --jsonl

目前 Resource Triage 没有肯定的完成回执,而且在某些资源根尚未完成时也可能输出行。所有权覆盖情况始终应描述为 unverified;保留任何更具体的诊断信息,绝不要将零行解读为“没有所有权问题”。

切片并合并行

按确切操作汇总不安全调用:

jq -s '
  map(select(.reason == "Unsafe call"))
  | sort_by(.detail)
  | group_by(.detail)
  | map({
      operation: .[0].detail,
      sites: length,
      members: (map(.member) | unique)
    })
' unsafe-members.jsonl

选择指南中讨论的 API 系列:

jq -s --arg pattern \
  'Unsafe\.(AsPointer|As|BitCast|Add|NullRef|SkipInit|ReadUnaligned|WriteUnaligned|CopyBlock)' '
  map(select(.detail | test($pattern)))
' unsafe-members.jsonl

选择 stackalloc(localloc)位置:

jq -s '
  map(select(.detail == "localloc"))
  | group_by(.member)
  | map({member: .[0].member, sites: map(.il)})
' unsafe-members.jsonl

组合为一个 Agent 数据包时,保留各证据系列的类型信息:

jq -n \
  --slurpfile unsafe unsafe-members.jsonl \
  --slurpfile ownership resource-triage.jsonl \
  --slurpfile interop pinvoke-methods.jsonl \
  '{
    unsafe: $unsafe,
    ownership: $ownership,
    interop: $interop
  }'

这些是切片,而非按显示文本联接。保留每行的 Member、IL、 token、Candidate、Finding、Acquire IL、Boundary IL 和边界字段。深入分析前, 先解析确切的 Type 和 Member 选择器;不要根据格式化后的 Member 标签臆造对应关系。

深入分析一个候选项

为聚焦证据使用独立的机器输出,并保留 Markdown IL 供审阅。重复使用 capture 包装器,以便空结果或失败的深入分析也能显现:

capture candidate-unsafe.jsonl \
  dnx dotnet-inspect -y -- member MyType Method:1 --library MyLib.dll \
    -S "Unsafe Operations" --jsonl
capture candidate-exceptions.jsonl \
  dnx dotnet-inspect -y -- member MyType Method:1 --library MyLib.dll \
    -S "Exception Regions" --jsonl
capture candidate-attributes.jsonl \
  dnx dotnet-inspect -y -- member MyType Method:1 --library MyLib.dll \
    -S "Custom Attributes" --jsonl
capture candidate-calls.jsonl \
  dnx dotnet-inspect -y -- member MyType Method:1 --library MyLib.dll \
    -S "Call Graph" --fields "Unsafe,Throw,Catch,Finally,Loop" --jsonl
capture candidate-il.md \
  dnx dotnet-inspect -y -- member MyType Method:1 --library MyLib.dll \
    -S IL

仅在重构出的 C# 有助于解释 IL 时才加载 skill decompiler。如果问题取决于词法作用域、手写的保护条件、编译器警告或仓库测试实践,请使用源代码证据。

为 26 个指导问题选择路径

以下路径列出了最精简且有用的证据组合。它们并不表示匹配的证据就能证明违规,也不表示检查后为空的行就能证明安全。

#指引主题证据路径与边界
1未跟踪的托管指针检查 AsPointer 的不安全调用片段;深入追踪指针来源、固定、用途和逃逸。
2指针从 fixed 中逃逸检查不安全/固定证据,以及 IL 存储、返回和调用;词法 fixed 作用域可能需要源代码。
3运行时或库内部实现检查不安全调用、特性、引用和非公开调用证据;广泛依赖仍需审查判断。
4无效托管指针检查 Unsafe.Add 和相关按引用算术片段;深入追踪范围和控制流证据。
5重新解释型转换检查 Unsafe.As 和 BitCast 片段;在判断兼容性前,先关联精确的源/目标 Type 元数据。
6写屏障与 GC 引用原子性检查 cpblk、initblk、间接存储和复制 API;深入追踪目标来源和字段类型。
7对象生命周期检查对 GC.KeepAlive、SafeHandle、终结器、回调和互操作边界的调用;通常无法验证缺失情况。
8跨线程局部变量检查调用图、异步/状态机、指针/按引用及所有权证据;线程转移通常需要源代码或运行时证据。
9不安全地移除边界检查检查指针解引用和 Unsafe.Add 片段;检查保护条件和范围,然后要求提供运行时性能证据。
10内存访问合并检查 Unsafe/MemoryMarshal 调用和存储片段;使用运行时证据比较安全替代方案。
11非对齐内存访问检查非对齐 API 和间接操作片段;目标对齐和原子性仍需结合平台/上下文判断。
12二进制结构体序列化检查 MemoryMarshal/Unsafe 读、写、复制操作及精确的 Type 布局;开放泛型仍不完整。
13空托管指针检查 Unsafe.NullRef 和指针到按引用转换的片段;深入追踪用途和被丢弃的解引用操作。
14stackalloc检查 localloc;深入追踪循环归属、长度构造、span 转换和边界。
15固定大小缓冲区不安全声明可用于筛选候选项,但库特性无法发现字段级别的 FixedBufferAttribute;无法验证整个库的发现结果,因此对于已知候选项,请使用源代码或精确 Type 反编译。
16指针加长度 API指针签名和 P/Invoke 行可用于识别候选项;检查显式长度和终止假设。
17字符串修改检查指针存储以及字符串来源证据;通常需要源代码或反编译来确定目标。
18原始 IL 生成引用和调用可用于识别 Reflection.Emit 或 Cecil 的使用;生成的 IL 是否有效需要单独的证据。
19未初始化的局部变量检查 Unsafe.SkipInit 调用片段。库特性无法确定 SkipLocalsInit;无法验证整个库的普查结果,因此请使用源代码,或检查精确 Member 的特性和 IL 局部变量初始化,然后深入追踪读取、写入和池化缓冲区初始化。
20ArrayPool<T> 和池化关联资源分流、不安全调用、异常和返回;当前所有权覆盖情况始终无法验证。
21bool/整数转换检查涉及 Boolean 和整数 Type 的 Unsafe.As、BitCast 及非对齐读取片段。
22互操作检查 P/Invoke 行、签名、特性、不安全操作以及所有权/生命周期证据。
23线程安全调用图和可变资源证据可用于筛选候选项;不涵盖一般性的线程安全结论。
24SIMD/向量化调用和不安全操作可用于识别加载/存储;边界、对齐、原子性和收益需要结合上下文/运行时证据判断。
25模糊测试程序集证据无法确定仓库的模糊测试覆盖率;请单独检查测试和 CI。
26编译器警告普通程序集不会保留警告;需要构建诊断信息或 SARIF。
报告审查结果

对于每个适用的问题,请报告:

  1. 指导主题和准确的检查对象;
  2. 所有者给出的行及准确坐标;
  3. 生成有界候选集的 jq 切片或联接;
  4. Agent 标注的解读;
  5. 已完成的内容或 unverified 边界;以及
  6. 当证据无法判定问题时,下一步有针对性的探查。

不要因为没有出现匹配行,就报告全部 26 个主题均无问题。省略确实不适用的主题,并将其与证据不可用或不完整的适用问题区分开来。

评论

支持 Markdown