web-dev-qa-db-ja.com

アクセス違反の例外をキャッチしますか?

int *ptr;
*ptr = 1000;

microsoft固有のものを使用せずに標準C++を使用してメモリアクセス違反例外をキャッチできますか。

80
Ahmed Said

いや。 C++は、何か悪いことをしても例外をスローしません。これにより、パフォーマンスが低下します。アクセス違反やゼロ除算のようなものは、キャッチできる言語レベルのものではなく、「マシン」例外に似ています。

36
unwind

読んで泣いてください!

私はそれを考え出した。ハンドラーからスローしない場合、ハンドラーは続行し、例外もスローします。

魔法は、あなたがあなた自身の例外を投げてそれを処理するときに起こります。

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <tchar.h>

void SignalHandler(int signal)
{
    printf("Signal %d",signal);
    throw "!Access Violation!";
}

int main()
{
    typedef void (*SignalHandlerPointer)(int);

    SignalHandlerPointer previousHandler;
    previousHandler = signal(SIGSEGV , SignalHandler);
    try{
        *(int *) 0 = 0;// Baaaaaaad thing that should never be caught. You should write good code in the first place.
    }
    catch(char *e)
    {
        printf("Exception Caught: %s\n",e);
    }
    printf("Now we continue, unhindered, like the abomination never happened. (I am an EVIL genius)\n");
    printf("But please kids, DONT TRY THIS AT HOME ;)\n");

}
102
Juxta

Try-> catchを使用して、Visual Studioであらゆる種類の例外(ゼロ除算、アクセス違反など)をキャッチする非常に簡単な方法があります。 ...)ブロック。マイナーなプロジェクト設定の微調整で十分です。プロジェクト設定で/ EHaオプションを有効にするだけです。 プロジェクトのプロパティ-> C/C++->コード生成-> C++例外を有効にするを「SEH例外ではい」に変更するを参照してください。それでおしまい!

詳細はこちら: http://msdn.Microsoft.com/en-us/library/1deeycx5(v = vs.80).aspx

63

このタイプの状況は実装に依存するため、トラップするためにはベンダー固有のメカニズムが必要になります。 Microsoftでは、これにはSEHが関係し、* nixには信号が関係します

一般に、アクセス違反の例外をキャッチすることは非常にの悪い考えです。 AV例外から回復する方法はほとんどありません。回復しようとすると、プログラムのバグを見つけるのが難しくなります。

8
JaredPar

少なくとも私にとっては、別の回答で言及されているsignal(SIGSEGV ...)アプローチVisual C++ 2015のWin32では機能しませんでした。私にとってdidは、_eh.h_にある_set_se_translator()を使用することでした。それはこのように動作します:

ステップ1)必ず有効にしてくださいSEH例外(/ EHa)ではい inプロジェクトのプロパティ/ C++ /コード生成/ C++例外を有効にするVolodymyr Frytskyyによる回答で述べたように。

ステップ2_set_se_translator()を呼び出して、新しい例外translatorの関数ポインター(またはラムダ)を渡します。基本的に低レベルの例外を取得し、_std::exception_などのキャッチしやすいものとして再スローするため、トランスレーターと呼ばれます。

_#include <string>
#include <eh.h>

// Be sure to enable "Yes with SEH Exceptions (/EHa)" in C++ / Code Generation;
_set_se_translator([](unsigned int u, EXCEPTION_POINTERS *pExp) {
    std::string error = "SE Exception: ";
    switch (u) {
    case 0xC0000005:
        error += "Access Violation";
        break;
    default:
        char result[11];
        sprintf_s(result, 11, "0x%08X", u);
        error += result;
    };
    throw std::exception(error.c_str());
});
_

ステップ)通常どおり例外をキャッチします。

_try{
    MakeAnException();
}
catch(std::exception ex){
    HandleIt();
};
_
7
Michael

述べたように、Windowsプラットフォームでこれを行うための非マイクロソフト/コンパイラベンダーの方法はありません。ただし、通常のtry {} catch(exception ex){}の方法でこれらのタイプの例外をキャッチして、エラー報告やアプリのより適切な終了を行うことは明らかに役立ちます(JaredParによると、アプリはおそらく問題を抱えています) 。 _se_translator_functionを単純なクラスラッパーで使用して、tryハンドラーで次の例外をキャッチできます。

DECLARE_EXCEPTION_CLASS(datatype_misalignment)
DECLARE_EXCEPTION_CLASS(breakpoint)
DECLARE_EXCEPTION_CLASS(single_step)
DECLARE_EXCEPTION_CLASS(array_bounds_exceeded)
DECLARE_EXCEPTION_CLASS(flt_denormal_operand)
DECLARE_EXCEPTION_CLASS(flt_divide_by_zero)
DECLARE_EXCEPTION_CLASS(flt_inexact_result)
DECLARE_EXCEPTION_CLASS(flt_invalid_operation)
DECLARE_EXCEPTION_CLASS(flt_overflow)
DECLARE_EXCEPTION_CLASS(flt_stack_check)
DECLARE_EXCEPTION_CLASS(flt_underflow)
DECLARE_EXCEPTION_CLASS(int_divide_by_zero)
DECLARE_EXCEPTION_CLASS(int_overflow)
DECLARE_EXCEPTION_CLASS(priv_instruction)
DECLARE_EXCEPTION_CLASS(in_page_error)
DECLARE_EXCEPTION_CLASS(illegal_instruction)
DECLARE_EXCEPTION_CLASS(noncontinuable_exception)
DECLARE_EXCEPTION_CLASS(stack_overflow)
DECLARE_EXCEPTION_CLASS(invalid_disposition)
DECLARE_EXCEPTION_CLASS(guard_page)
DECLARE_EXCEPTION_CLASS(invalid_handle)
DECLARE_EXCEPTION_CLASS(Microsoft_cpp)

元のクラスは、この非常に便利な記事から来ました。

http://www.codeproject.com/KB/cpp/exception.aspx

7
Damien

例外処理メカニズムではありませんが、Cが提供するsignal()メカニズムを使用できます。

> man signal

     11    SIGSEGV      create core image    segmentation violation

NULLポインターに書き込むと、おそらくSIGSEGVシグナルが発生します

3
Martin York