0

I wrote code

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;
}

and i'm waiting for output

code1
code2
code4

but i have only

code1

and infinite loop.

Why is it?

adding volatile keyname to s and j didn't fix it.

user1761982
  • 143
  • 1
  • 2
  • 10
  • 1
    Have a look at the assembly code generated by the compiler. It's probable that the s in (1/s) is treated as a constant zero because there's no way that it can have any other value in normal C/C++ control flow. – arx Nov 14 '14 at 18:01
  • What compiler are you using? I use C++Builder and what you have shown works fine for me, I see `code1`, `code2` and `code4` as expected. – Remy Lebeau Nov 14 '14 at 18:04
  • @RemyLebeau VC compiler from visual studio 2008 – user1761982 Nov 14 '14 at 18:22

2 Answers2

4

The infinite loop is caused because the exception is rethrown every time you resume execution. It doesn't matter that you set the value of s = 1 in the filter because the execution is resumed from the instruction that caused the trap, which in this case is the divide by zero. If you reorganize the code as follows you'll see that the exception is continually being thrown:

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;
}

The result should read:

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

The exception continues to be thrown because execution is resumed on the instruction that divides by zero, not on the instruction that loads the value of s. The steps are:

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
...

I don't think you'll be able to resume from that exception.

JP Flouret
  • 578
  • 4
  • 6
  • 1
    You would be able to resume if you know which register is being used for the divide, and adjust the value of that register instead of adjusting the `s` variable. But that requires you to have some intimate knowledge of how particular compilers generate machine instructions for this code. In this particular example, the code should just use `EXCEPTION_EXECUTE_HANDLER` to handle the exception and move on. – Remy Lebeau Nov 14 '14 at 18:59
0

If you want the last part to execute try enclosing the whole thing in another

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

For more information look here and here.

The line with 'code 2' would not be displayed because execution is interrupted by the exception on the previous line.

DNT
  • 2,356
  • 14
  • 16
  • Yes, i know about __finally , but now i learn __try ... __except(code). When code = 0 or 1, my program works fine, but when code = EXCEPTION_CONTINUE_EXECUTION it is strange. Actually, i try to wrote an example of code when it works – user1761982 Nov 14 '14 at 17:54
  • 2
    CONTINUE_EXECUTION assumes you did something to fix the error and you attempting that in (s=1, i). Here, I'd check the assembly translation to see what really happens. You cannot assume that 's' retains the intended semantics at assembly level. It may already have been translated as a value in a register, or a constant. – DNT Nov 14 '14 at 18:00