VS2008 Включить исключение C++ с SEH

Я не хочу, чтобы моя программа аварийно завершала работу, поэтому я включил исключение C++ с помощью SEH. Так что, если есть какие-то ошибки, например, обращение к нулевому указателю, моя программа может перехватить его с помощью catch(...).

Я хочу знать: 1. Есть ли какой-либо недостаток включения C++ исключения с SEH? 2. Как я могу узнать подробности исключения, когда оно перехватывается catch(...)?

1 ответ

Решение
  1. Насколько я знаю, никаких проблем с производительностью нет, потому что я почти уверен, что исключения C++ в любом случае реализованы через SEH. Все, что вы делаете, это позволяете расширению получать исключения на уровне ОС. Однако есть один существенный недостаток, затронутый в двух.

  2. Вы обычно используете __try а также __except поймать SEH исключения; больше информации здесь. Обратите внимание, что в этом и заключается недостаток: исключения, перехваченные таким образом, не запускают деструкторы. Однако, что вы можете сделать, это использовать функцию _set_se_translator переводить исключения SEH в исключения C++.

Вот что-то из одного из моих проектов, который делает это (использует Boost и C++0x в MSVC 2010):

bool ignore_exception(unsigned pCode)
{
    const unsigned ignoreList[] = {EXCEPTION_BREAKPOINT,
        EXCEPTION_FLT_DENORMAL_OPERAND, EXCEPTION_FLT_DIVIDE_BY_ZERO,
        EXCEPTION_FLT_INEXACT_RESULT, EXCEPTION_FLT_OVERFLOW, EXCEPTION_FLT_UNDERFLOW,
        EXCEPTION_INT_OVERFLOW, EXCEPTION_SINGLE_STEP};

    auto result = std::search_n(std::begin(ignoreList), std::end(ignoreList),
                    1, pCode);
    return result != std::end(ignoreList);              
}

std::string code_string(unsigned pCode)
{
    switch (pCode)
    {
    case EXCEPTION_ACCESS_VIOLATION:
        return "Access violation";
    case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
        return "Out of array bounds";
    case EXCEPTION_BREAKPOINT:
        return "Breakpoint";
    case EXCEPTION_DATATYPE_MISALIGNMENT:
        return "Misaligned data";
    case EXCEPTION_FLT_DENORMAL_OPERAND:
        return "Denormalized floating-point value";
    case EXCEPTION_FLT_DIVIDE_BY_ZERO:
        return "Floating-point divide-by-zero";
    case EXCEPTION_FLT_INEXACT_RESULT:
        return "Inexact floating-point value";
    case EXCEPTION_FLT_INVALID_OPERATION:
        return "Invalid floating-point operation";
    case EXCEPTION_FLT_OVERFLOW:
        return "Floating-point overflow";
    case EXCEPTION_FLT_STACK_CHECK:
        return "Floating-point stack overflow";
    case EXCEPTION_FLT_UNDERFLOW:
        return "Floating-point underflow";
    case EXCEPTION_GUARD_PAGE:
        return "Page-guard access";
    case EXCEPTION_ILLEGAL_INSTRUCTION:
        return "Illegal instruction";
    case EXCEPTION_IN_PAGE_ERROR:
        return "Invalid page access";
    case EXCEPTION_INT_DIVIDE_BY_ZERO:
        return "Integer divide-by-zero";
    case EXCEPTION_INT_OVERFLOW:
        return "Integer overflow";
    case EXCEPTION_INVALID_DISPOSITION:
        return "Invalid exception dispatcher";
    case EXCEPTION_INVALID_HANDLE:
        return "Invalid handle";
    case EXCEPTION_NONCONTINUABLE_EXCEPTION:
        return "Non-continuable exception";
    case EXCEPTION_PRIV_INSTRUCTION:
        return "Invalid instruction";
    case EXCEPTION_SINGLE_STEP:
        return "Single instruction step";
    case EXCEPTION_STACK_OVERFLOW:
        return "Stack overflow";
    default:
        return "Unknown exception";
    }
}

void stack_fail_thread()
{
    std::cerr << "Unhandled exception:\n"
                << code_string(EXCEPTION_STACK_OVERFLOW) << '\n';
    std::cerr << "Terminating." << std::endl;

    // can print a stack dump of the failed
    // thread to see what went wrong, etc...

    std::exit(EXIT_FAILURE);
}

void exception_translator(unsigned pCode, _EXCEPTION_POINTERS*)
{
    // minimize function calls if it's a stack overflow
    if (pCode == EXCEPTION_STACK_OVERFLOW)
    {
        // do some additional processing in another thread,
        // because the stack of this thread is gone
        boost::thread t(stack_fail_thread);
        t.join(); // will never exit
    }
    else if (!ignore_exception(pCode))               
    {
        // can add a stack dump to the exception message,
        // since these tend to be pretty severe, etc...
        BOOST_THROW_EXCEPTION(std::runtime_error(code_string(pCode)));
    }
}

void hook_signals()
{
    _set_se_translator(exception_translator);
}

Я снял несколько вещей, но вы поняли идею. Вы можете извлечь всю ту же информацию таким образом.

Другие вопросы по тегам