Различное поведение наблюдается при использовании SEH (структурированная обработка исключений)

Я проводил некоторые эксперименты с SEH. В своем коде я написал блок, вызывающий ошибку, в предложении __try и обработчик в __except ().

__try{
Test *pTest = 0;
int k = pTest->GetValue();
cout << "continue after exception" << endl;
}
__except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION,EXCEPTION_EXECUTE_HANDLER)
{
cout << "caught!!" << endl;
}
cout << "Exception handled" << endl;

Второй параметр __except () является одним из следующих:

EXCEPTION_CONTINUE_SEARCH Исключение не распознано. Продолжайте искать в стеке обработчик, сначала содержащий операторы try-кроме, затем обработчики со следующим наивысшим приоритетом.

EXCEPTION_CONTINUE_EXECUTION Исключение распознается, но отклоняется. Продолжите выполнение в том месте, где произошло исключение.

EXCEPTION_EXECUTE_HANDLER Исключение распознано. Передайте управление обработчику исключений, выполнив составной оператор __except, затем продолжите выполнение в том месте, где произошло исключение.

Когда я использую EXCEPTION_CONTINUE_EXECUTION / EXCEPTION_EXECUTE_HANDLER, он не продолжает выполнение в точке возникновения исключения (возможно, я неверно истолковываю значение точки возникновения исключения).
Когда я запускаю его в режиме отладки, вывод

caught
Exception handled

Когда я запускаю его в режиме выпуска, вывод

continue after exception
Exception handled

Я не мог понять, почему он ведет себя по-другому. Кто-нибудь, пожалуйста, помогите.

2

Решение

@Joachim правильно указывает на проблему оператора запятой.

Я думаю __except() должен выглядеть так:

__except((GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ?
EXCEPTION_EXECUTE_HANDLER :
EXCEPTION_CONTINUE_SEARCH)

Это заставит обработчик исключения выполняться, если исключение является нарушением прав доступа. Если это не так, исключение будет распространяться до ближайшего внешнего __tryесли есть.

Я боюсь что pTest является указателем на класс, и для его выполнения может не потребоваться разыменование GetValue() и компилятор распознает это, когда оптимизации включены в режиме выпуска. Или, может быть, даже это видит GetValue() как бесполезный и не генерирует никакого кода для его вызова. Также возможно, что компилятор видит, что разыменование NULL-указателя приводит к неопределенному поведению, и решает наказать вас за это во время компиляции, испортив ваш код, он имеет полное право сделать это. например, gcc печально известен этим.

4

Другие решения

Выражение

GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION,EXCEPTION_EXECUTE_HANDLER

не делает то, что вы ожидаете. Что это делает, это сравнить результат GetExceptionCode() с EXCEPTION_ACCESS_VIOLATION, но результат всего выражения EXCEPTION_EXECUTE_HANDLER,

Подробнее о запятом в Википедии.

Что вы хотите сделать, это, вероятно,

GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION || GetExceptionCode() == EXCEPTION_EXECUTE_HANDLER
1

По вопросам рекламы [email protected]