arkweb-thread-safety-review について
arkweb-thread-safety-review は、ArkWeb/Chromium C++ の単一ファイルを対象とするスレッド安全性監査 Skill です。10 個の標準ルールに基づき、スレッド、非同期境界、オブジェクトの所有関係と寿命の明確な証拠がある違反だけを判定し、JSON で出力します。
主な機能
- 01ArkWeb/Chromium C++ の単一ファイル監査
- 0210 個の標準ルールで違反を判定
- 03スレッド・所有関係・寿命の証拠を確認
- 04監査結果を JSON で出力
活用シーン
- 01C++ ファイルの非同期コールバックを確認
- 02UI、GPU、Audio オブジェクトへのスレッド間アクセスを検査
- 03mojo::Connector のシーケンス制約を確認
- 04ルールレベル付きで違反を集約
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ openharmonyinsight/ openharmony-skills --skill arkweb-thread-safety-reviewインストール後、Claude Code で/arkweb-thread-safety-reviewを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
evals/evals.jsonREADME.mdexamples/README.mdexamples/bad/README.mdstandard_rule1_unretained_this.mdstandard_rule10_scoped_refptr.mdstandard_rule2_gpu_mojo_thread.mdstandard_rule3_drdc_thread.mdstandard_rule4_ndk_ui_thread.mdstandard_rule5_nweb_ui_thread.mdstandard_rule6_ui_object_access.mdstandard_rule7_mojo_connector.mdstandard_rule8_audio_thread.mdstandard_rule9_cef_post_task.mdexamples/good/no_violation_id_transfer.mdno_violation_uncertain_thread.mdstandard_rule1_unretained_this.mdstandard_rule10_scoped_refptr.mdstandard_rule2_gpu_mojo_thread.mdstandard_rule3_drdc_thread.mdstandard_rule4_ndk_ui_thread.mdstandard_rule5_nweb_ui_thread.mdstandard_rule6_ui_object_access.mdstandard_rule7_mojo_connector.mdstandard_rule8_audio_thread.mdstandard_rule9_cef_post_task.mdreferences/output_examples.mdteam_mapping.md詳細
ArkWeb スレッドセーフティコード監査スキル
概要
この Skill は、ArkWeb/Chromium の C++ 単一ファイルを対象にスレッドセーフティを監査し、本文の 10 個の標準ルールに対する明確な違反のみを報告します。主な目的は、疑わしい API を列挙することではなく、現在のファイルにスレッド/sequence、非同期境界、オブジェクトの所有関係、ライフサイクルを示す証拠がそろっているかを判断することです。
監査前の判断
- ファイルの種類と監査範囲が、ArkWeb/Chromium の C++ 単一ファイル監査に該当するか確認します。
- まず、関数やコールバックが実行される可能性のあるスレッド/sequence を判断します。特に UI、IO、GPU、Audio、DrDC、IPC、外部コールバックスレッドに注意します。
- 非同期タスクでは、まず実行経路とオブジェクトのライフサイクルを確認してから、裸の
this、base::Unretained(this)、スレッドをまたいだ保持のリスクを判断します。 - UI スレッドオブジェクト、NWeb オブジェクト、GPU/Audio リソース、
mojo::Connectorについては、まずアクセススレッドとオブジェクトの所有スレッドが一致するか確認します。 - 明確なオブジェクト、スレッド経路、非同期境界、またはライフサイクルの証拠を示せる場合に限り、違反を報告します。
監査の判断経路
- トリガーとなる箇所を特定します。非同期境界、スレッド切り替え、mojo/IPC、外部コールバック、UI/GPU/Audio/NWeb オブジェクトへのアクセス、
scoped_refptrのスレッド間転送を優先的に検索します。 - 実行スレッドを判断します。
CurrentlyOn、task runner、CEF_POST_TASK、BrowserThread、mojo receiver/connector のバインド位置、関数名から現在の sequence を推測します。推測できない場合は、違反を直接報告しません。 - オブジェクトの所有関係を判断します。アクセス対象のオブジェクトが UI、GPU、Audio、DrDC、または作成元のスレッドでの使用を要求するか確認します。
- ライフサイクルを判断します。非同期タスク内に裸の
this、base::Unretained(this)、スレッド間のscoped_refptrがあり、現在のファイルで owner、キャンセル機構、またはWeakPtrによる保護を確認できない場合に限り、報告します。 - ルールを選択します。同じ証拠は最も具体的な standard_rule のみに分類します。複数の一般的なルールで重複して報告しないでください。
スキャンの実行順序
トリガー箇所を検索 -> スレッド/sequence の証拠を確立 -> オブジェクトの所有関係とライフサイクルを確認 -> ルールマトリクスを適用 -> 該当ルールの例のみを読む -> 必要に応じて team_mapping を読む -> 完全な JSON を出力
証拠の強さとルールの選択
- 強い証拠:現在のファイルに、明確なトリガー箇所、スレッドまたは非同期境界、制約のあるオブジェクト、転送またはライフサイクル保護の欠如が同時に確認できる場合、違反を報告できます。
- 弱い証拠:疑わしい API やオブジェクトは確認できても、現在のファイルから実行スレッド、owner のライフサイクル、スレッド間の経路を確認できない場合は、違反を報告しません。
- 報告禁止:同期による即時呼び出し、同一 sequence 内での
scoped_refptrのコピーのみ、WebContents/Profile などのオブジェクトを ID に変換してからスレッド間で渡すケース、非同期タスクが既存のWeakPtr/キャンセル機構/明確な owner によって保護されているケース。 - 報告前のセルフチェック:各違反について、対象オブジェクトは何か、現在のスレッド/sequence は何か、非同期またはスレッド間の境界はどこか、どの保護が欠けているか、現在のファイルのどの行が証拠か、をすべて説明できなければなりません。
- ルールが重複する場合は、より具体的なルールを選択します。
mojo::Connectorのスレッド間使用は rule7 を優先し、GPU mojo のスレッド誤りは rule2 を優先し、compositor_gpu_thread_は rule3 を優先し、NWeb/BrowserContext/NavigationController は rule5 を優先し、一般的な Chromium UI オブジェクトへのアクセスは rule6 に分類し、非同期の裸のthisに関するライフサイクルは rule1 に分類し、スレッド間の参照カウントオブジェクトは rule10 に分類します。 - 競合例:GPU mojo コールバック内で
mojo::Connectorをスレッド間で使用している場合、証拠の中心が connector の sequence-affinity の破損であれば rule7 を報告します。証拠の中心が IPC コールバックによる GPU リソースの直接処理であれば rule2 を報告します。 - 競合例:同じ非同期タスクで裸の
thisをキャプチャし、さらにscoped_refptr<T>を保持している場合、裸のthisによる UAF の証拠は rule1 で報告します。スレッド間の参照カウント/デストラクターのモデルが安全でない場合に限り、さらに rule10 を報告し、同じ原因の重複報告を避けます。 - 3 つ以上のルールが重複する場合は、「オブジェクト固有のスレッド制約 > リソースのスレッド制約 > 一般的なライフサイクル/参照カウント」の順で根本原因を選びます。同じコード片については、現在のファイルの証拠で完全に裏付けられる最も具体的なルールのみを報告します。
- 複雑な重複の例:IPC コールバック内で GPU リソースに触れ、
mojo::Connectorを使用し、さらに裸のthisをキャプチャしている場合、現在のファイルで GPU リソースの誤ったスレッドでの使用のみが証明されるなら rule2 を報告します。connector の作成 sequence と使用 sequence が異なることも証明できる場合に限り、さらに rule7 を報告します。非同期コールバックがオブジェクトの破棄後に実行される可能性も証明できる場合に限り、さらに rule1 を報告します。
不確かな証拠の振り分け
- 作成/バインドスレッドの証拠がない場合:オブジェクトの所有スレッドを証明できないため、
mojo::Connector、NWeb、Audio、GPU/DrDC オブジェクトのスレッド間違反は報告しません。 - task runner の所有関係が不明な場合:
PostTaskが確認できても、対象 runner が UI/GPU/Audio/DrDC のどれに対応するか分からない場合、それを修正済みとも違反とも判断しません。CurrentlyOn、RunsTasksInCurrentSequence、BrowserThread、または名前による証拠を引き続き探し、見つからなければ報告しません。 - owner のライフサイクルが不明な場合:非同期コールバックがオブジェクトをキャプチャしていても、現在のファイルで破棄経路、キャンセル機構、owner との関係を確認できない場合は、裸の
this/base::Unretained(this)と非同期境界が同時に成立するときに限り報告します。それ以外は、標準外のライフサイクル問題へ拡大しません。 - 管理対象オブジェクトの型が不明な場合:
scoped_refptr<T>変数のみが確認でき、Tの参照カウント基底クラス、デストラクターの sequence、スレッド間での使用経路が確認できない場合は、rule10 を報告しません。
違反なしと判定する前の再確認
空の violations を出力する前に、現在のファイルで以下の証拠を見落としていないか、少なくとも再確認します。
- コンストラクター、
Init*、Start*、Bind*、BindReceiverにある sequence、task runner、receiver、connector のバインド箇所。 - メンバーの
*_task_runner_、receiver_、connector_、weak_factory_の初期化箇所、使用スレッド、破棄/キャンセル経路。 - コールバックが
On*、Did*、Notify*、Run*、Create*On*Threadなどの helper を経由して再転送され、実際の実行スレッドが同じファイルの別の関数に隠れていないか。 - オブジェクトの破棄、
InvalidateWeakPtrs、タスクのキャンセル、owner の保持関係が現在のファイルで確認できるか。証拠がなければ、違反は空のままとし、推測に基づくフィールドは出力しません。
誤検出の抑制
- 「スレッドチェックがない」または「複数スレッドから呼ばれる可能性がある」という理由だけで違反を報告してはなりません。
- 同期呼び出しを非同期ライフサイクルの問題と誤認してはなりません。
- 違反を確認する証拠が不十分な場合は、違反を報告しません。複数ファイルを確認しなければ確定できないリスクについても、現在のファイルで確認できる証拠を基準にします。
- 本文の 10 個の標準ルールに含まれない問題を、違反として出力してはなりません。
- 最終的な監査結果は JSON のみを出力し、Markdown、説明文、コードフェンスを出力してはなりません。
絶対に報告しないケース
- rule1:
base::Unretained(this)のみが確認でき、コールバックが同期的に即時実行される場合、オブジェクトのライフサイクルが現在のファイルで確認できる owner によって保護されている場合、またはWeakPtr/キャンセル機構がすでに使われている場合は報告しません。それ以外では、パフォーマンス最適化や同期的なバインドを UAF と誤認することになります。 - rule5/rule6:frame tree node id、process id、routing id、URL、文字列、設定スナップショットなどの値型のみをスレッド間で渡す場合、UI オブジェクトのスレッド間アクセスとして報告しません。これらの値は UI オブジェクトのライフサイクルから切り離されており、スレッド間での間接参照には該当しません。
- rule7:
mojo::Connectorのメンバー宣言、または同一 sequence 内での使用のみが確認でき、作成 sequence と使用 sequence の不一致を確認できない場合は報告しません。mojo::Connectorのリスクは sequence-affinity の破損によるもので、DCHECK、メッセージの順序乱れ、競合によるクラッシュを引き起こす可能性があります。型そのものが問題なのではありません。 - rule8:Audio メソッド名のみが確認でき、現在の入口が Audio 以外のスレッドから呼び出されていること、または audio task runner 経由でタスクが投入済みであることを確認できない場合は報告しません。Audio のライフサイクルメソッド名はラップされていることが多いため、入口スレッドの証拠が必要です。
- rule10:
scoped_refptr<T>自体は違反ではありません。Tの参照カウント、デストラクターの sequence、またはメソッドのアクセスモデルがスレッド間使用に対応しておらず、かつ現在のファイルにスレッド間での保持/転送の証拠がある場合に限り報告します。それ以外では、通常の参照カウントによるライフサイクル管理をスレッド間のメモリリスクと誤認することになります。
辅助材料
examples/ 保存按标准规则拆分的 good/bad 自包含示例。
示例读取规则:
- MANDATORY READ:命中某条标准规则的关键代码模式并准备判断是否报告时,必须读取该规则对应的 bad 示例;需要确认边界或修复方式时,再读取对应 good 示例。
- 需要区分误报边界时,优先读取 bad 示例,再对照 good 示例。
- DO NOT LOAD:未命中某条规则关键词时,不要加载该规则示例;不要加载无关规则示例,也不要用示例中的路径、类名或行号替代当前被审查文件的证据。
| 触发规则 | 关键模式 | 必读示例 |
|---|---|---|
| standard_rule1 | base::Unretained(this)、BindOnce、BindRepeating、异步回调保存后执行 | examples/bad/standard_rule1_unretained_this.md;必要时对照 examples/good/standard_rule1_unretained_this.md |
| standard_rule2 | GPU mojo 回调、IPC 线程处理 GPU 资源 | examples/bad/standard_rule2_gpu_mojo_thread.md;必要时对照 examples/good/standard_rule2_gpu_mojo_thread.md |
| standard_rule3 | compositor_gpu_thread_ 直接调用 | examples/bad/standard_rule3_drdc_thread.md;必要时对照 examples/good/standard_rule3_drdc_thread.md |
| standard_rule4 | NDK 接口、外领域回调、非 UI 线程调用 | examples/bad/standard_rule4_ndk_ui_thread.md;必要时对照 examples/good/standard_rule4_ndk_ui_thread.md |
| standard_rule5 | Perf、BrowserContext、NavigationController、NWeb 对象访问 | examples/bad/standard_rule5_nweb_ui_thread.md;必要时对照 examples/good/standard_rule5_nweb_ui_thread.md |
| standard_rule6 | WebContents、Profile、RenderFrameHost 等 Chromium UI 对象访问 | examples/bad/standard_rule6_ui_object_access.md;必要时对照 examples/good/standard_rule6_ui_object_access.md |
| standard_rule7 | mojo::Connector 创建线程和使用线程不一致 | examples/bad/standard_rule7_mojo_connector.md;必要时对照 examples/good/standard_rule7_mojo_connector.md |
| standard_rule8 | Audio 启动、暂停、停止、关闭操作 | examples/bad/standard_rule8_audio_thread.md;必要时对照 examples/good/standard_rule8_audio_thread.md |
| standard_rule9 | CEF_POST_TASK 依赖 Web 实例 | examples/bad/standard_rule9_cef_post_task.md;必要时对照 examples/good/standard_rule9_cef_post_task.md |
| standard_rule10 | scoped_refptr 跨线程传递或多线程持有 | examples/bad/standard_rule10_scoped_refptr.md;必要时对照 examples/good/standard_rule10_scoped_refptr.md |
| 证据不足 | 只有可疑 API、值类型跨线程传递、缺少线程/owner 证据 | 对照 examples/good/no_violation_uncertain_thread.md 和 examples/good/no_violation_id_transfer.md |
规则判定矩阵
| 规则 | 触发证据 | 必要报告证据 | 不报告条件 |
|---|---|---|---|
| standard_rule1 | PostTask、delay、ThreadPool、mojo/IPC、NDK 或外部回调中绑定裸 this/base::Unretained(this) | 当前文件看不到 WeakPtr、取消机制、owner 生命周期覆盖,且回调可能在对象销毁后执行 | 同步立即执行、生命周期证据充分、已使用 WeakPtr 或取消机制 |
| standard_rule2 | GPU mojo 回调、IPC 线程收到 GPU 操作 | GPU 资源或 GPU 接口在 IPC/当前回调线程直接使用,未投递到 GPU 线程 | 只转发参数、不触碰 GPU 资源,或已投递到目标 GPU task runner |
| standard_rule3 | compositor_gpu_thread_ 成员调用 | 调用发生在 UI/IPC/非 DrDC 入口,且未通过 DrDC task runner 转发 | 当前代码已经在 DrDC task runner 上执行 |
| standard_rule4 | NDK 接口、外领域交互回调、应用侧回调入口 | 当前入口不是 UI 线程,仍直接调用 NDK/外部回调 | 已检查 UI 线程或已 PostTask 到 UI 线程 |
| standard_rule5 | Perf、BrowserContext、NavigationController、NWeb 对象访问 | 当前入口不是 UI 线程,直接读写这些 UI 归属对象 | 只传递 ID/值快照,或访问已经转发到 UI 线程 |
| standard_rule6 | WebContents、Profile、RenderFrameHost、RenderProcessHost 等 Chromium UI 对象 | 非 UI 线程直接解引用或调用对象方法 | 只跨线程传递稳定 ID/弱引用 token,或回到 UI 线程再访问 |
| standard_rule7 | mojo::Connector 创建、绑定、Accept、Close、发送消息 | 当前文件同时显示创建/绑定 sequence 与使用 sequence 不一致 | 只有声明、同 sequence 使用,或缺少创建线程证据 |
| standard_rule8 | Audio start/pause/stop/close、音频回调入口、audio task runner | 非 Audio 线程直接执行音频生命周期操作 | 已通过 audio task runner 投递,或入口可确认在 Audio 线程 |
| standard_rule9 | CEF_POST_TASK 投递依赖 Web 实例的任务 | 投递前未检查对应 Web 实例已创建/仍可用,当前文件存在初始化竞态 | 投递前已有实例检查或任务不依赖 Web 实例 |
| standard_rule10 | scoped_refptr<T> 跨线程传递、多线程持有、异步任务捕获 | 必须确认 T 的引用计数基类和对象访问路径是否线程安全;base::RefCounted 对象不得跨线程持有/释放 | 仅同 sequence 内复制,或 T 明确使用 base::RefCountedThreadSafe 并支持跨线程访问 |
规则等级
规则等级用于标识违规风险优先级,不影响是否报告 violation。所有 violation 仍必须满足本文的明确证据要求。
| 等级 | 标准规则ID | 报告策略 |
|---|---|---|
| P1 | standard_rule1, standard_rule2, standard_rule3, standard_rule6, standard_rule7, standard_rule10 | 优先报告和修复;通常涉及 UAF、跨线程 UI/GPU/DrDC/mojo sequence 破坏或引用计数竞争 |
| P2 | standard_rule4, standard_rule5, standard_rule8, standard_rule9 | 正常报告;通常涉及 UI/Audio 线程契约、NWeb/BrowserContext 访问约束或 Web 实例生命周期前置条件 |
报告要求:
- 所有 violation 必须带
rule_level字段,并与上表保持一致。 - 不得仅凭“缺少线程检查”“可能多线程调用”报告,必须指出明确对象、跨线程路径或生命周期证据。
标准规则索引
以“规则判定矩阵”为主规则源;本节只提供 rule_id 和 rule_name,避免与矩阵产生漂移。
| rule_id | rule_name |
|---|---|
| standard_rule1 | 异步任务裸 this 生命周期约束 |
| standard_rule2 | GPU mojo 任务线程约束 |
| standard_rule3 | compositor_gpu_thread_ DrDC 线程约束 |
| standard_rule4 | NDK 接口与外领域回调 UI 线程约束 |
| standard_rule5 | NWeb 相关对象 UI 线程约束 |
| standard_rule6 | Chromium UI 线程对象访问约束 |
| standard_rule7 | mojo::Connector 跨线程约束 |
| standard_rule8 | Audio 操作 Audio 线程约束 |
| standard_rule9 | CEF_POST_TASK Web 实例创建约束 |
| standard_rule10 | scoped_refptr 线程安全约束 |
模块责任划分
优先按代码所属功能模块和文件路径选择团队;若规则与多个团队相关,以直接拥有被访问对象或接口的团队为准。当前文件无法可靠判断时,选择最接近的功能团队,并在 issue 中写明依据,不要因为归属不确定新增非标准规则。
输出 violation 时必须填写 team。若无法从路径、对象或接口直接确定团队,必须读取 references/team_mapping.md;仍无法判断时填最接近团队,并在 issue 中说明依据。
评审输出格式
本 Skill 专注于单文件扫描。
输出仅采用 JSON,便于工具链解析和结果汇总。
格式约束(必须严格遵守)
- 只输出 JSON,禁止添加 Markdown、解释性文字、代码围栏或额外章节。
- 违规规则必须来自本文档定义的标准规则。
- 必须附上规则编号:
rule_id使用standard_rule<N>,rule_name使用对应标准规则名称。 - 必须附上规则等级:每条违规必须按“规则等级”表输出
rule_level。 - 无违规时也必须输出完整 JSON 结构,
violations数组为空。 - 证据不足时不得扩展 schema:不要输出
uncertain、finding、note、risk等自定义字段;证据不足就是无 violation。 - 不得虚构输出字段:
anti_pattern只能摘录当前文件可见代码;required_fix无法给出精确代码时,写最小修复方向,如“PostTask 到目标线程”或“改用 WeakPtr”,不要编造不存在的函数名、runner 名、路径或团队归属。 - 输出不确定时按需读取示例:如果不确定无违规 JSON、
required_fix或多规则冲突该如何落 schema,读取references/output_examples.md。
JSON 格式
{
"scan_info": {
"file_path": "<文件绝对路径>",
"skill": "arkweb-thread-safety-review"
},
"summary": {
"total_violations": 0,
"by_rule": {
"<规则编号>": <数量>
},
"by_team": {
"<团队名称>": <数量>
}
},
"violations": [
{
"id": 1,
"rule_id": "<规则编号,如 standard_rule1>",
"rule_name": "<规则名称>",
"rule_level": "<规则等级,如 P2>",
"location": {
"file": "<文件名>",
"line": <行号>,
"function": "<函数名>"
},
"issue": "<问题描述>",
"anti_pattern": "<违规代码片段>",
"required_fix": "<最小修复方向或当前文件可见的修复片段>",
"impact": "<违反后果>",
"team": "<责任团队>"
}
]
}
无违规时:violations 数组为空 [],summary.total_violations 为 0,by_rule 和 by_team 为空对象 {}。