EXCEPTION_CONTINUE_EXECUTION странное поведение

0

Я написал код

void SEHtest(int i) {
  int s = 0;
  __try {
    cout << "code1" << endl;
    int j = 1 / s;
    cout << "code2" << endl;
  } __except((s = 1, i)) {
    cout << "code3" << endl;
  }
  cout << "code4" << endl;
  return;
}
int main() {
  SEHtest(-1);
  return 0;
}

и я жду выхода

code1
code2
code4

но у меня есть только

code1

и бесконечный цикл.

Почему это?

добавление volatile keyname в s и j не исправить.

  • 1
    Посмотрите на ассемблерный код, сгенерированный компилятором. Вероятно, что s в (1 / s) трактуется как постоянный ноль, потому что нет никакого способа, чтобы он мог иметь любое другое значение в обычном потоке управления C / C ++.
  • 0
    Какой компилятор вы используете? Я использую C ++ Builder и то , что вы показали , отлично работает для меня, я вижу code1 , code2 и code4 , как ожидалось.
Показать ещё 1 комментарий
Теги:
winapi
seh

2 ответа

3
Лучший ответ

Бесконечный цикл вызван тем, что исключение повторяется каждый раз, когда вы возобновляете выполнение. Не имеет значения, что вы устанавливаете значение s = 1 в фильтре, потому что выполнение возобновляется из инструкции, вызвавшей ловушку, которая в этом случае является делением на ноль. Если вы реорганизуете код следующим образом, вы увидите, что исключение постоянно бросается:

int ExceptionFilter(int& s) {
  cout << "exception filter with s = " << s << endl;
  s++;
  return -1; // EXCEPTION_CONTINUE_EXECUTION
}

void SEHtest() {
  int s = 0;
  __try {
    cout << "before exception" << endl;
    int j = 1 / s;
    cout << "after exception" << endl;
  } __except(ExceptionFilter(s)) {
    cout << "exception handler" << endl;
  }
  cout << "after try-catch" << endl;
  return;
}

int main() {
  SEHtest();
  return 0;
}

Результат должен выглядеть следующим образом:

before exception
exception filter with s = 0
exception filter with s = 1
exception filter with s = 2
...

Исключение продолжается, поскольку выполнение возобновляется в команде, которая делит на ноль, а не на команду, которая загружает значение s. Шаги:

1  set a register to 0
2  store that register in s (might be optimized out)
3  enter try block
4  output "before exception"
5  load a register from s
6  divide 1 by register (trigger exception)
7  jump to exception filter
8  in filter increment/change s
9  filter returns -1
10 execution continues on line 6 above
6  divide 1 by register (trigger exception)
7  jump to exception filter
8  in filter increment/change s
9  filter returns -1
10 execution continues on line 6 above
...

Я не думаю, что вы сможете возобновить это исключение.

  • 0
    Вы сможете продолжить, если знаете, какой регистр используется для деления, и скорректировать значение этого регистра вместо настройки переменной s . Но это требует от вас глубоких знаний о том, как определенные компиляторы генерируют машинные инструкции для этого кода. В этом конкретном примере код должен просто использовать EXCEPTION_EXECUTE_HANDLER чтобы обработать исключение и двигаться дальше.
0

Если вы хотите, чтобы последняя часть выполнялась, попробуйте включить все это в другой

__try { 
 < your code>
}
__finally{
    < code that will be executed at end>
}

Для получения дополнительной информации смотрите здесь и здесь.

Строка с "кодом 2" не будет отображаться, потому что выполнение прерывается исключением в предыдущей строке.

  • 0
    Да, я знаю об __finally, но теперь я изучаю __try ... __except (код). Когда код = 0 или 1, моя программа работает нормально, но когда код = EXCEPTION_CONTINUE_EXECUTION, это странно. На самом деле, я пытаюсь написать пример кода, когда он работает
  • 2
    CONTINUE_EXECUTION предполагает, что вы сделали что-то, чтобы исправить ошибку, и вы пытались это сделать в (s = 1, i). Здесь я бы проверил перевод ассемблера, чтобы увидеть, что на самом деле происходит. Вы не можете предполагать, что 's' сохраняет намеченную семантику на уровне сборки. Возможно, он уже был переведен как значение в регистре или константа.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню