ページ 11

CRTセキュリティ強化関数のエラーキャッチサンプル

Posted: 2016年5月10日(火) 22:58
by いわん
VC++にCRTのセキュリティ強化された関数(strcpy_s等)というのがありますが、これらの関数でバッファオーバーランなどのエラーを検出すると
無効なパラメータハンドラが呼び出されます(debug版ではアサーションダイアログを表示し「続行」選択で無効なパラメータハンドラが呼ばれます)。
規定のハンドラの動作ではメッセージを表示してアプリケーションはクラッシュしますが、コンソール入力やファイル読み込みなどで異常データが予期
できる場合はエラーを検出してプログラムをクラッシュさせずに処理したい場合があります。
サンプルプログラムは、独自の CRT無効なパラメータハンドラで例外(std::invalid_argument)をスローしてプログラムを終了することなくエラーとして
処理するものです。
Compiler : Visual Stadio/C++ 2008
使用条件:コピー・流用・改変等、一切制限しません。

コード:

// コンパイルオプションに C++の例外を有効にする 構造化例外あり(/EHa) を使用すること
#include <stdio.h>
#include <tchar.h>
#include <string>

// 独自の CRT無効なパラメータ ハンドラ
void myInvalidParameterHandler(const wchar_t * expression, const wchar_t * function, const wchar_t * file, unsigned int line, uintptr_t pReserved)
{
	std::wstring ws(L"_invalid_parameter :");
	if (function != NULL)
	{
		ws += L" ";
		ws += function;
	}
	if (expression != NULL)
	{
		ws += L" ";
		ws += expression;
	}
	throw std::invalid_argument( std::string( ws.begin(), ws.end() ) );
}

int _tmain(int argc, _TCHAR* argv[])
{
	// CRT 無効なパラメータハンドラを変更する
	_invalid_parameter_handler hOldPrmError;
	hOldPrmError = _set_invalid_parameter_handler(myInvalidParameterHandler);
	// デバッグ版のアサーションメッセージを無効化する
	int nOldReportMode;
	nOldReportMode = _CrtSetReportMode(_CRT_ASSERT, 0);

	_tsetlocale(LC_ALL, _T("JPN"));	// UNICODEを使用すると日本語が表示されないのでロケールを設定する
	TCHAR buf[10];
	int len = sizeof(buf)/sizeof(*buf)-1;
	_tprintf_s(_T("最大 %d文字までの文字列を入力してください。入力なしで終了。\n"), len);
	while (true)
	{
		try
		{
			_getts_s(buf, len+1);	// バッファのサイズを超える文字列を入力すると CRT無効なパラメータハンドラが呼び出される
			if (buf[0] == 0)	break;
			_putts(_T("OK"));
		}
		catch (std::invalid_argument& exp)
		{
			fprintf_s(stderr, "%s\n", exp.what());
		}
	}

	// アサーションメッセージ出力をもとに戻す
	_CrtSetReportMode(_CRT_ASSERT, nOldReportMode);
	// CRT 無効なパラメータハンドラをもとに戻す
	_set_invalid_parameter_handler(hOldPrmError);

	return 0;
}