Last-modified: 2014-11-03 (月) 15:17:57
C++/動的配列の範囲外アクセス(読み書き両方)を検出する(RobustArrayNew)

概要

動的配列の範囲外アクセス(書き込み)、メモリリーク、二重解放はMicrosoftのcrtdbgで動的検出できます。
ただし、動的配列の範囲外アクセス(読み込み)はcrtdbgでは検出できません。
これを検出可能にする機構 RobustArrayNewを作成しました。
ヘッダを1つインクルードし、デバッグビルドするだけで、動的検出が可能です。
ここでは、RobustArrayNewの仕組みと使い方を紹介します。

仕組み

Windowsはページ単位でメモリの属性を変更出来るため、operator new[]を上書きし
[詰め物領域] + [サイズ領域] + [実領域] + [ガード領域]という構成のメモリを確保します。
その際、[詰め物領域] + [サイズ領域] + [実領域]を、ページサイズ境界に合わせておきます。
その後、[ガード領域]を読み取り/書き込み不可にします。
こうすることで、[実領域]を1バイトでも超えてアクセスすると、確実に例外が発生するようになります。

使い方(お試し)

  1. #include "RobustArrayNew.h"をエントリポイント(main, _tmain, WinMain, dllmain, etc...)のあるソースに定義
  2. デバッグビルド&実行
  3. 範囲外アクセスをすると例外で止まるので、Just-In-Timeデバッグで該当コードが表示されます

使い方(推奨)

RobustArrayNewとcrtdbgは相互補完の関係にあります。
しかし、この2つを同時に使用することはできません。
なので、以下の様なマクロを使い、どちらか一方が有効になるようにすることをおすすめします。
RobustArrayNewの中に、以下のマクロを含むサンプルも収録してあります。

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
-
|
!
 
 
 
 
 
 
 
 
// エントリポイント(main, _tmain, WinMain, dllmain, etc...)のあるソースに以下のマクロを定義します
// プロジェクト内に#define new DEBUG_NEWがある場合は、削除してください
#ifdef _DEBUG
#ifdef ENABLED_ROBUST_ARRAY_NEW
    #include "RobustArrayNew.h"        
#else
    #define _CRTDBG_MAP_ALLOC
    #include <crtdbg.h>
    #define new ::new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif    // ENABLED_ROBUST_ARRAY_NEW
#endif    // _DEBUG
Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
-
!
 
 
 
 
 
 
 
 
 
 
// エントリポイント(main, _tmain, WinMain, dllmain, etc...)先頭付近に以下のマクロを定義します
#ifdef _DEBUG
#ifndef ENABLED_ROBUST_ARRAY_NEW
    _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
    _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
    _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
    _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
    _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
    _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif    // ENABLED_ROBUST_ARRAY_NEW
#endif    // _DEBUG

ダウンロード

RobustArrayNew

検証時の環境