แชร์ผ่าน


Never use catch(…)

Yun Jin had an interesting note on the catch(…) operator. There is an additional thing that I would like to mention. On earlier versions of the Microsoft C++ compiler, this language construct was used as a general garbage sink of all exceptions, including SEH ones, like access violations. However, there is a new exception handing model in the latest versions of the compiler: /EHs, or the synchronous exception handling model. What /EHs does is several things. First of all, it tries to optimize the C++ code around exceptions as much as possible (which means faster code). Second, it will not expect that every executed instruction can end up in an SEH exception being thrown. This means that if you compile with /EHs and you have some C++ objects on the stack in a COM call, their destructor will not be invoked when the stack goes away when an SEH is being thrown.

Which brings me to the next point - the catch(...) is a bad way to "make things work" by catching every possible exception. First of all, it behaves differently in /EHs vs. /EHa. Second, if you catch an exception, then what is it? If it is a stack oveflow, then there is no point in continuing the execution of your program. If is an Access violation, then probably you just had a potentially exploitable buffer overrun, and simply continuing the execution of your program will largely increase the attach surface of your code.

Finally, note that on XP, there is a subtlety around stack related exceptions. At the end of your usable stack pages there is a special "guard page" that triggers an exception when the stack touches that region. The exception handing code uses this to extend the stack and re-create the guard page further. This also meant that if you catch this stack guard exception, then you need to call a C runtime API called _resetstkoflw( ) which will do the necessary fixups. But, with catch(...) it is unclear what you have to do since you do not know if you are in a stack guard exception or or not...

Access violations are even worse. For example if the thread T1 touches the guard page of thread T2, and you "ate" the associated exception, then the T2 guard page remains in an intermediate state. Any further touch of this page (for example if the T2 stack grows) will cause an unconditional process termination.

Moral of the story? Never use catch(...) with /EHSa

[update]

I forgot to add an important observation - if your code eats exceptions like Access Violations, etc then these exception will never make it to Dr. Watson web site (or your custom Dr. Watson exception collector). This is important since Dr. Watson (or its variations) are an invaluable tool in determining the most frequent exceptions in your shipped code.