# 機能設計書 139-動的ライブラリ読み込み

## 概要

uv_dlopen()/uv_dlclose()により動的ライブラリ（共有ライブラリ）の読み込み・解放を行う機能の設計書である。

### 本機能の処理概要

本機能は、実行時に動的ライブラリ（Unix: .so/.dylib、Windows: .dll）を読み込み・解放するためのクロスプラットフォームAPIを提供する。

**業務上の目的・背景**：プラグインアーキテクチャ、モジュラーなアプリケーション設計、ランタイムでのライブラリ切り替えなど、動的リンクが必要なユースケースはソフトウェア開発において一般的である。POSIXのdlopen/dlcloseとWindowsのLoadLibraryEx/FreeLibraryは引数の型やエラー報告方法が大きく異なるため、libuvが統一的なインターフェースを提供する。特にWindows版では、ファイル名のUTF-8→UTF-16変換やLOAD_WITH_ALTERED_SEARCH_PATHフラグの使用など、プラットフォーム固有の処理が含まれる。

**機能の利用シーン**：Node.jsのネイティブアドオンの動的読み込み、プラグインシステムの実装、オプショナルな機能の条件付き読み込み、テスト時のモックライブラリの差し替えに利用される。

**主要な処理内容**：
1. uv_dlopen()による動的ライブラリの読み込み（ファイル名指定）
2. uv_dlclose()による動的ライブラリの解放とエラーメッセージのクリーンアップ
3. エラーメッセージの管理（lib->errmsgへの格納）

**関連システム・外部連携**：Unix系ではdlopen()/dlclose()、WindowsではLoadLibraryExW()/FreeLibrary()を使用する。

**権限による制御**：ファイルシステムの読み取り権限およびライブラリの実行権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 27 | 共有ライブラリ | 主機能 | uv_dlopen()/uv_dlclose()による動的ライブラリ読み込み・解放のAPI定義 |

## 機能種別

ユーティリティ操作（動的ライブラリ管理）

## 入力仕様

### 入力パラメータ

#### uv_dlopen()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| filename | const char* | Yes | ライブラリのファイルパス（NUL終端UTF-8文字列） | なし（OS側で検証） |
| lib | uv_lib_t* | Yes | ライブラリハンドル格納先 | NULLの場合は未定義動作 |

#### uv_dlclose()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| lib | uv_lib_t* | Yes | 解放するライブラリハンドル | NULLの場合は未定義動作 |

### 入力データソース

呼び出し元アプリケーションからの直接指定。

## 出力仕様

### 出力データ

#### uv_dlopen()

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | int | 成功時0、失敗時-1 |
| lib->handle | void*/HMODULE | 読み込まれたライブラリハンドル |
| lib->errmsg | char* | 失敗時のエラーメッセージ（成功時NULL） |

#### uv_dlclose()

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | void | なし（エラーは無視される） |

### 出力先

呼び出し元への戻り値およびuv_lib_t構造体のメンバー更新。

## 処理フロー

### 処理シーケンス

```
uv_dlopen():
1. [Unix]
   a. dlerror()でエラーステータスをリセット
   b. lib->errmsg = NULL
   c. lib->handle = dlopen(filename, RTLD_LAZY)
   d. handleがNULL → uv__dlerror()でエラーメッセージ取得、-1返却
2. [Windows]
   a. lib->handle = NULL, lib->errmsg = NULL
   b. uv_wtf8_length_as_utf16()でUTF-8→UTF-16長を算出
   c. uv_wtf8_to_utf16()で変換
   d. LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH)
   e. 失敗時uv__dlerror()でFormatMessage使用のエラーメッセージ設定

uv_dlclose():
1. [Unix]
   a. uv__free(lib->errmsg), lib->errmsg = NULL
   b. lib->handleがNULLでなければdlclose(lib->handle)
   c. lib->handle = NULL
   d. エラーは無視（メモリリーク防止不可のため）
2. [Windows]
   a. lib->errmsgがあればLocalFree(), lib->errmsg = NULL
   b. lib->handleがNULLでなければFreeLibrary()
   c. lib->handle = NULL
```

### フローチャート

```mermaid
flowchart TD
    A[uv_dlopen] --> B{プラットフォーム}
    B -->|Unix| C[dlerror リセット]
    C --> D[dlopen RTLD_LAZY]
    D --> E{handle != NULL?}
    E -->|Yes| F[0返却]
    E -->|No| G[uv__dlerror: エラーメッセージ取得]
    G --> H[-1返却]
    B -->|Windows| I[UTF-8→UTF-16変換]
    I --> J[LoadLibraryExW]
    J --> K{成功?}
    K -->|Yes| F
    K -->|No| L[FormatMessage でエラー設定]
    L --> H
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-139-01 | 遅延バインド | Unix版ではRTLD_LAZYフラグで遅延シンボル解決を使用 | Unix |
| BR-139-02 | 検索パス変更 | Windows版ではLOAD_WITH_ALTERED_SEARCH_PATHでDLL検索パスを変更 | Windows |
| BR-139-03 | エラー無視 | dlclose()/FreeLibrary()のエラーは無視される（メモリリーク回避不可） | 常時 |
| BR-139-04 | エラーメッセージ管理 | lib->errmsgはuv__free()（Unix）またはLocalFree()（Windows）で解放される | 常時 |
| BR-139-05 | UTF-8入力 | Windows版ではファイル名をUTF-8として受け取りUTF-16に変換する | Windows |

### 計算ロジック

特になし。

## データベース操作仕様

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| -1 (戻り値) | 読み込み失敗 | ファイル不在、権限不足、依存ライブラリ不在等 | uv_dlerror()でメッセージ確認 |
| ERROR_NO_UNICODE_TRANSLATION | 変換エラー | Windows版でUTF-8→UTF-16変換失敗 | 正しいUTF-8パスを指定 |
| ERROR_BAD_EXE_FORMAT | 形式エラー | DLLフォーマットが不正 | 正しいDLLを指定 |

### リトライ仕様

リトライは通常不要。依存ライブラリのパス問題を解決後に再試行可能。

## トランザクション仕様

該当なし。

## パフォーマンス要件

dlopen/LoadLibraryExはファイルI/Oとシンボルテーブルの読み込みを伴うため、初回は比較的コストが高い。ただし、OSがキャッシュするため2回目以降は高速。

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

動的ライブラリの読み込みはコード実行を伴うため、信頼できないパスからの読み込みはセキュリティリスクとなる。DLLハイジャック攻撃に注意が必要。Windows版のLOAD_WITH_ALTERED_SEARCH_PATHはこのリスクの軽減に寄与する。

## 備考

- uv_dlopen()の戻り値はlibuvの他のAPI（負のエラーコード）とは異なり、失敗時は-1を返す。エラー詳細はuv_dlerror()で取得する。
- Unix版ではdlerror()を事前呼び出ししてエラー状態をリセットする。
- Windows版ではFormatMessageAで英語のエラーメッセージを取得し、英語MUIが利用不可の場合はシステムロケールにフォールバックする。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | unix.h | `include/uv/unix.h` | uv_lib_tの構造体定義（L212-215: void* handle + char* errmsg） |
| 1-2 | win.h | `include/uv/win.h` | uv_lib_tの構造体定義（L314-317: HMODULE handle + char* errmsg） |
| 1-3 | uv.h | `include/uv.h` | API宣言（L1842-1843） |

**読解のコツ**: uv_lib_t構造体はUnix/Windows共にhandle + errmsgの2フィールドで、プラットフォーム間でハンドルの型のみ異なる。

#### Step 2: Unix版実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | dl.c (Unix) | `src/unix/dl.c` | uv_dlopen()（L33-38） |
| 2-2 | dl.c (Unix) | `src/unix/dl.c` | uv_dlclose()（L41-50） |
| 2-3 | dl.c (Unix) | `src/unix/dl.c` | uv__dlerror()（L65-80） |

**主要処理フロー**:
- **L33-38 (open)**: dlerror()リセット → errmsg=NULL → dlopen(RTLD_LAZY) → handleがNULLなら-1
- **L41-50 (close)**: uv__free(errmsg) → dlclose(handle) → handle=NULL、エラー無視
- **L65-80 (uv__dlerror)**: dlerror()で文字列取得 → uv__strdup()で複製してlib->errmsgに格納

#### Step 3: Windows版実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | dl.c (Win) | `src/win/dl.c` | uv_dlopen()（L28-48） |
| 3-2 | dl.c (Win) | `src/win/dl.c` | uv_dlclose()（L51-62） |
| 3-3 | dl.c (Win) | `src/win/dl.c` | uv__dlerror()（L92-135） |

**主要処理フロー**:
- **L28-48 (open)**: uv_wtf8_length_as_utf16 → uv_wtf8_to_utf16 → LoadLibraryExW(LOAD_WITH_ALTERED_SEARCH_PATH) → 失敗時uv__dlerror
- **L51-62 (close)**: LocalFree(errmsg) → FreeLibrary(handle) → handle=NULL
- **L92-135 (uv__dlerror)**: FormatMessageA(FROM_SYSTEM/ENGLISH) → 英語MUI不可時フォールバック → ERROR_BAD_EXE_FORMATの%1をfilename置換

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

```
uv_dlopen(filename, lib)
    |
    +-- [Unix]
    |       +-- dlerror()  // リセット
    |       +-- dlopen(filename, RTLD_LAZY)
    |       +-- [失敗時] uv__dlerror(lib)
    |               +-- dlerror() → uv__strdup() → lib->errmsg
    |
    +-- [Windows]
            +-- uv_wtf8_length_as_utf16(filename)
            +-- uv_wtf8_to_utf16(filename, filename_w, r)
            +-- LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH)
            +-- [失敗時] uv__dlerror(lib, filename, GetLastError())
                    +-- FormatMessageA() → lib->errmsg

uv_dlclose(lib)
    +-- [Unix] uv__free(errmsg) → dlclose(handle)
    +-- [Windows] LocalFree(errmsg) → FreeLibrary(handle)
```

### データフロー図

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

filename (const char*)   --> dlopen() / LoadLibraryExW() --> lib->handle（成功）
lib (uv_lib_t*)              UTF-8→UTF-16変換 (Win)          lib->errmsg（失敗時）
                                                              戻り値: 0 / -1
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダ | API宣言（L1842-1843） |
| unix.h | `include/uv/unix.h` | ヘッダ | uv_lib_t型定義（L212-215） |
| win.h | `include/uv/win.h` | ヘッダ | uv_lib_t型定義（L314-317） |
| dl.c (Unix) | `src/unix/dl.c` | ソース | Unix版動的ライブラリ実装（L33-80） |
| dl.c (Win) | `src/win/dl.c` | ソース | Windows版動的ライブラリ実装（L28-135） |
