Search code examples
c++winapiseh

EXCEPTION_CONTINUE_EXECUTION strange behavour


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.


Solution

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