MAX_PATH とか _MAX_PATH とか FILENAME_MAX とか

「ファイルのフルパスを保持しておきたい、けど動的に確保するのは面倒」みたいなときに MAX_PATH_MAX_PATHFILENAME_MAX マクロが使用されがちです。

というか、僕の場合はそうしていました。

ただ、おかしいなと常々思ってはいました。

というのも、上記マクロは値として 260 を保持しているのですが、実際に NTFS 上では 260 文字を超過するフルパスを作成することが可能だからです。

ひとつ例を挙げてみます。

wchar_t szPath[MAX_PATH];
DWORD rc = GetModuleFileName(NULL, szPath, len);
if (rc == 0) {
    // エラー処理
}

これは現在実行中のモジュールのパスを取得する処理です。

GetModuleFileName は、渡されたバッファにパスを書き込みますが、パスがバッファに書ききれない場合、書けるところまで書いて終了します。つまりモジュールのパスが 260 文字を超える場合、完全なパスが取得できません。

これを回避するためには、以下のように処理しなければなりません。

size_t len = MAX_PATH; // 初期値としては妥当
wchar_t *szPath = NULL;
while (szPath == NULL) {
    szPath = (wchar_t *)malloc(len * sizeof(wchar_t));
    DWORD rc = GetModuleFileName(NULL, szPath, len);
    if (rc == 0) {
        // エラー処理
    } else if (rc >= len - 1) { 
        // 書き込まれた文字がバッファいっぱいならバッファを再確保
        free(szPath);
        szPath = NULL;
        len *= 2;
    }
}

パスがバッファより長い可能性がある場合、メモリを再確保して再チャレンジします。また、確保したメモリはどこかで解放してやらなければなりません。



名前からして MAX_PATH、_MAX_PATH、FILENAME_MAX などは、パスが収まるには必要十分なサイズっぽい印象を与えられますが、それはまやかしです。パスがどれぐらいの長さになるのか、というのは実際に取ってみるまでわかりません。



一度手元のソースコードに対して MAX_PATH、_MAX_PATH、FILENAME_MAX を grep してみるとよいかもしれません。多くの環境・状況では 260 文字あれば足りてしまうので、問題になりにくいかもしれませんが、もし不用意にバッファサイズに割り当てているようならとてもとても危険です。