Thursday 29 July 2004 — This is more than 20 years old. Be careful.
Head’s up: this is a way geeky question. It’s about C++ calling conventions and exception handling. (Is it bad form for me to use this blog as my own personal help forum?)
I have a strange problem where C++ destructors are not being called for stack-allocated objects when an exception is thrown through my function. For example:
class StackThingy
{
public:
// Constructor will be called when the StackThingy
// is created on the stack.
StackThingy()
{
// (Point A)
}
// Destructor should be called when the StackThingy
// is unwound from the stack.
~StackThingy()
{
// (Point B)
}
};
void __stdcall
MyTestRoutine()
{
// Create the StackThingy
StackThingy thingy;
// Throw an exception. This should unwind the StackThingy
// object, calling its destructor.
throw CException();
}
When I run this code, Point A executes in the constructor, but execution never reaches Point B. It should, because the exception being thrown should unwind stack, calling the destructors on any stack-allocated object. But somehow, the exception would not properly destroy the thingy object.
I narrowed it down to the __stdcall calling convention. If I remove the __stdcall declaration to make it a regular C++ function, then the destructor is called as I would expect. I can find no mention of this behavior in the docs or on the wider web. The description of __stdcall talks about stack maintenance as a key difference between calling conventions, but doesn’t describe exception handling at all.
Is this expected behavior, or is there some other nefarious factor at work here?
Comments
It'd be shocking if throw turns into a nop in this case, but not much less shocking than the destructor not being called...
I had no luck finding information about this problem either.
BTW, what happens if an __stdcall routine is in the middle of a "normal" call chain, and the lower "normal" function throws? Does unwinding happen correctly across the __stdcall?
Obviously, I should test all these questions myself, but Visual C++ seems to be missing from this Linux box :)
I'd suggest e-mailing Raymond Chen...C++ exception handling and how it maps to/works with Win32's Structure Exception Handling is a rather complex realm.
The throw really occurs, and is caught by a calling function. The odd thing is that destructors are called for the stack objects if the function exits normally, but not if an exception is thrown.
i.e., with the parens? Does that change the code flow at all?
Note that the Microsoft docs don't explicitly say that the definition and declaration both include the __stdcall keyword, but the fact that __stdcall changes the calling conventions makes it seem likely that both are required.
Later on....:
"Finally, let's consider whether we can assume that extern "C" functions don't throw C++ exceptions (remember that such an assumption is built into /GX). Extern "C" functions in a C++ program are most likely being linked in from an object module or library. These functions are often written in a different language, such as C or assembler. Because the type of exception we are handling is a feature specifically of the C++ language only, it seems a reasonable assumption to say that an extern "C" function will not throw an exception.
Of course, if an extern "C" function is compiled by the C++ compiler, it is perfectly legal for that function, or one of its called functions, to throw a C++ exception. For those who must throw C++ exceptions from extern "C" functions, replace /GX, which is the same as using /EHsc, with just /EHs. /EHs enables C++ exception handling without the assumption that extern "C" functions will never throw a C++ exception. /EHc enables the assumption that extern "C" functions do not throw exceptions."
Let us know if this helps...
Add a comment: