# 帳票設計書 11-TSan Report

## 概要

本ドキュメントは、ThreadSanitizer (TSan) によるデータ競合検出レポートの設計仕様を定義する。TSanはマルチスレッドプログラムにおけるデータ競合を検出するためのランタイムツールであり、検出結果を人間が読みやすい形式でコンソールに出力する。

### 本帳票の処理概要

TSan Reportは、マルチスレッドプログラム実行時に検出されたデータ競合やスレッド関連のエラーを、開発者が問題を特定・修正できるよう詳細な情報とともに報告する帳票である。

**業務上の目的・背景**：マルチスレッドプログラミングにおけるデータ競合は、再現困難なバグの原因となり、デバッグが非常に困難である。TSan Reportは、コンパイル時の計装と実行時の監視により、これらの問題を自動的に検出し、発生箇所と原因を明確に報告することで、マルチスレッドプログラムの品質向上に貢献する。

**帳票の利用シーン**：開発者がTSanを有効にしてビルドしたプログラムを実行した際、データ競合やスレッドリーク、デッドロック等の問題が検出されると自動的にレポートが生成される。CI/CDパイプラインでのテスト実行時にも活用される。

**主要な出力内容**：
1. エラー種別（データ競合、スレッドリーク、デッドロック等）の識別
2. 競合するメモリアクセスの詳細（アドレス、サイズ、読み書き種別）
3. 各アクセスを行ったスレッドのスタックトレース
4. メモリ位置の情報（グローバル変数、ヒープ、スタック等）
5. 関連するミューテックスの情報
6. スレッドの作成元情報

**帳票の出力タイミング**：TSanが有効なプログラムの実行中に、データ競合等のエラーが検出された時点で即座に出力される。

**帳票の利用者**：C/C++マルチスレッドアプリケーション開発者、QAエンジニア、DevOpsエンジニア

## 帳票種別

エラーレポート / 診断レポート

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | コンソール/ターミナル | N/A | プログラム実行時に自動出力 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | テキスト（標準エラー出力） |
| 用紙サイズ | N/A |
| 向き | N/A |
| ファイル名 | N/A（標準エラー出力） |
| 出力方法 | コンソール出力 / ログファイルリダイレクト |
| 文字コード | システムロケール依存 |

### コンソール出力設定

| 項目 | 内容 |
|-----|------|
| カラー出力 | 有（ターミナル対応時） |
| 区切り線 | `==================` |
| スタックトレース形式 | 設定可能（`stack_trace_format`フラグ） |

## 帳票レイアウト

### レイアウト概要

TSan Reportは、検出されたエラーごとに以下の構成でテキスト出力される。

```
==================
WARNING: ThreadSanitizer: {エラー種別} (pid={プロセスID})
  {アクセス情報（最初のアクセス）}
    {スタックトレース}

  {アクセス情報（2番目のアクセス）}
    {スタックトレース}

  {メモリ位置情報}

  {ミューテックス情報}

  {スレッド情報}

SUMMARY: ThreadSanitizer: {エラー種別} {ファイル名:行番号} {関数名}
==================
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | 区切り線 | レポート開始の区切り | 固定文字列 | `==================` |
| 2 | 警告メッセージ | エラー種別とプロセスID | ReportDesc::typ, internal_getpid() | `WARNING: ThreadSanitizer: {type} (pid={pid})` |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 備考 |
|----|-------|------|-------------|---------|-----|
| 1 | アクセス種別 | 読み書きの種別 | ReportMop::write, atomic | `Write`/`Read`/`Atomic write`/`Atomic read` | - |
| 2 | アクセスサイズ | アクセスしたバイト数 | ReportMop::size | `of size {size}` | - |
| 3 | アクセスアドレス | メモリアドレス | ReportMop::addr | `at {address}` | 16進数表示 |
| 4 | スレッド名 | アクセスしたスレッド | ReportMop::tid | `by {thread_name}` | - |
| 5 | ミューテックスセット | 保持中のミューテックス | ReportMop::mset | `(mutexes: ...)` | オプション |
| 6 | スタックトレース | コールスタック | ReportMop::stack | フレームごとに1行 | - |

### フッター部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | サマリー | エラーサマリー | ChooseSummaryStack() | `SUMMARY: ThreadSanitizer: {type} {location}` |
| 2 | 区切り線 | レポート終了の区切り | 固定文字列 | `==================` |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| TSan有効化 | `-fsanitize=thread`オプションでビルド | Yes |
| データ競合検出 | 実行時にデータ競合が検出された | Yes |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | 検出順 | 検出された順序 |

### 改ページ条件

N/A（コンソール出力のため改ページなし）

## データベース参照仕様

### 参照テーブル一覧

本帳票はデータベースを使用せず、実行時のメモリ状態から情報を取得する。

| データソース | 用途 | 取得方法 |
|-------------|------|---------|
| ReportDesc | レポート全体の情報 | 実行時に構築 |
| ReportMop | メモリ操作情報 | シャドウメモリから取得 |
| ReportLocation | メモリ位置情報 | アドレス解析 |
| ReportThread | スレッド情報 | スレッドレジストリから取得 |
| ReportMutex | ミューテックス情報 | 同期プリミティブ監視 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| - | - | - | 計算項目なし |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[データ競合検出] --> B[ReportDesc構築]
    B --> C[スタックトレース取得]
    C --> D[メモリ位置解析]
    D --> E[スレッド情報取得]
    E --> F[PrintReport呼び出し]
    F --> G[ヘッダー出力]
    G --> H[アクセス情報出力]
    H --> I[位置情報出力]
    I --> J[ミューテックス情報出力]
    J --> K[スレッド情報出力]
    K --> L[サマリー出力]
    L --> M[終了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| スタック復元失敗 | シンボル情報がない場合 | `[failed to restore the stack]` | デバッグ情報付きでリビルド |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | エラー検出ごとに1レポート |
| 目標出力時間 | 即座（ミリ秒単位） |
| 同時出力数上限 | 1（排他制御あり） |

## セキュリティ考慮事項

- レポートにはメモリアドレス情報が含まれるため、本番環境での出力は控える
- スタックトレースにはソースファイルパスが含まれる可能性がある
- ログファイルへのリダイレクト時はアクセス制御に注意

## 備考

- TSan Reportは16種類のエラータイプをサポート（ReportType列挙型参照）
- Go言語向けの出力形式も別途サポート（`SANITIZER_GO`マクロで切り替え）
- カラー出力はDecorator classで制御（Blue, Cyan, Green, Yellow, Magenta）

---

## コードリーディングガイド

本帳票を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、レポート出力に使用されるデータ構造を把握することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | tsan_report.h | `compiler-rt/lib/tsan/rtl/tsan_report.h` | ReportType列挙型で16種類のエラータイプを確認（24-41行目）。ReportDesc, ReportMop, ReportLocation, ReportThread, ReportMutex各構造体の定義を理解 |

**読解のコツ**:
- `ReportDesc`クラス（113-134行目）がレポート全体のコンテナとなる
- `Vector`テンプレートはLLVM独自の動的配列実装

#### Step 2: エントリーポイントを理解する

処理の起点となる関数を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | tsan_report.cpp | `compiler-rt/lib/tsan/rtl/tsan_report.cpp` | PrintReport関数（282-361行目）がレポート出力のエントリーポイント |

**主要処理フロー**:
1. **282-289行目**: レポートヘッダー出力（WARNING行）
2. **291-330行目**: エラータイプ別の詳細出力（デッドロック等）
3. **332-333行目**: メモリ操作情報（Mop）の出力
4. **335-336行目**: スリープ同期情報の出力（オプション）
5. **338-339行目**: メモリ位置情報の出力
6. **341-344行目**: ミューテックス情報の出力
7. **346-347行目**: スレッド情報の出力
8. **352-354行目**: サマリー行の出力

#### Step 3: 各出力関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | tsan_report.cpp | `compiler-rt/lib/tsan/rtl/tsan_report.cpp` | PrintStack（103-118行目）：スタックトレース出力 |
| 3-2 | tsan_report.cpp | `compiler-rt/lib/tsan/rtl/tsan_report.cpp` | PrintMop（142-162行目）：メモリ操作情報出力 |
| 3-3 | tsan_report.cpp | `compiler-rt/lib/tsan/rtl/tsan_report.cpp` | PrintLocation（164-207行目）：メモリ位置情報出力 |
| 3-4 | tsan_report.cpp | `compiler-rt/lib/tsan/rtl/tsan_report.cpp` | PrintThread（230-254行目）：スレッド情報出力 |
| 3-5 | tsan_report.cpp | `compiler-rt/lib/tsan/rtl/tsan_report.cpp` | PrintMutex（221-228行目）：ミューテックス情報出力 |

**主要処理フロー**:
- **62-101行目**: ReportTypeString関数でエラー種別を文字列に変換
- **22-30行目**: Decorator classでカラー出力を制御

### プログラム呼び出し階層図

```
PrintReport (tsan_report.cpp:282)
    │
    ├─ ReportTypeString (tsan_report.cpp:62)
    │      └─ エラー種別の文字列変換
    │
    ├─ PrintStack (tsan_report.cpp:103)
    │      └─ StackTracePrinter::RenderFrame
    │
    ├─ PrintMop (tsan_report.cpp:142)
    │      ├─ MopDesc (tsan_report.cpp:130)
    │      ├─ PrintMutexSet (tsan_report.cpp:120)
    │      └─ PrintStack
    │
    ├─ PrintSleep (tsan_report.cpp:256)
    │      └─ PrintStack
    │
    ├─ PrintLocation (tsan_report.cpp:164)
    │      └─ PrintStack (ヒープ/FDの場合)
    │
    ├─ PrintMutex (tsan_report.cpp:221)
    │      └─ PrintStack
    │
    ├─ PrintThread (tsan_report.cpp:230)
    │      └─ PrintStack
    │
    ├─ ChooseSummaryStack (tsan_report.cpp:264)
    │
    └─ ReportErrorSummary (sanitizer_common)
```

### データフロー図

```
[入力]                      [処理]                           [出力]

シャドウメモリ ───────▶ ReportDesc構築 ─────────────────┐
                              │                         │
スレッドレジストリ ──▶ ReportThread追加 ───────────────┤
                              │                         │
ミューテックス監視 ──▶ ReportMutex追加 ────────────────┤
                              │                         ▼
スタックトレース ───▶ ReportStack構築 ──────────▶ PrintReport ──▶ stderr
                              │                         │
アドレス解析 ─────────▶ ReportLocation構築 ─────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| tsan_report.h | `compiler-rt/lib/tsan/rtl/tsan_report.h` | ヘッダー | レポート用データ構造定義 |
| tsan_report.cpp | `compiler-rt/lib/tsan/rtl/tsan_report.cpp` | ソース | レポート出力実装 |
| tsan_rtl.h | `compiler-rt/lib/tsan/rtl/tsan_rtl.h` | ヘッダー | TSanランタイム定義 |
| tsan_defs.h | `compiler-rt/lib/tsan/rtl/tsan_defs.h` | ヘッダー | 基本定義・定数 |
| sanitizer_stacktrace_printer.h | `compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_printer.h` | ヘッダー | スタックトレース出力 |
| sanitizer_report_decorator.h | `compiler-rt/lib/sanitizer_common/sanitizer_report_decorator.h` | ヘッダー | カラー出力制御 |
