Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Throwing from DLL causes heap corruption

257 views
Skip to first unread message

Kenneth Porter

unread,
Jan 11, 2008, 5:16:19 PM1/11/08
to
I have a DLL linked to my own app that works fine when throwing from DLL to
application. But with a customer application I get a heap corruption
exception when the thrown exception goes out of scope in the catch clause.
I've copied the stack below. To the best of my knowledge, both app and DLL
are linked against the VC6 multi-threaded debug DLL runtime. Any idea
what's going wrong here?

_CrtIsValidHeapPointer(const void * 0x09b56480) line 1697
_free_dbg_lk(void * 0x09b56480, int -572662307) line 1044 + 9 bytes
_free_dbg(void * 0x09b56480, int -572662307) line 1001 + 13 bytes
operator delete(void * 0x09b56480) line 49 + 16 bytes
MSVCRTD! exception::~exception(void) + 45 bytes
AxisSafetyException::~AxisSafetyException() + 208 bytes
MSVCRTD! DestructExceptionObject(struct EHExceptionRecord *,unsigned char)
+ 85 bytes
MSVCRTD! __FrameUnwindToState + 807 bytes
MSVCRTD! __FrameUnwindToState + 458 bytes
MSVCRTD! __InternalCxxFrameHandler + 800 bytes
MSVCRTD! __InternalCxxFrameHandler + 227 bytes
MSVCRTD! __CxxFrameHandler + 44 bytes
NTDLL! 7c9037bf()
NTDLL! 7c90378b()
NTDLL! 7c90eafa()
MSVCRTD! _CxxThrowException@8 + 57 bytes

Giovanni Dicanio

unread,
Jan 12, 2008, 6:06:00 AM1/12/08
to

"Kenneth Porter" <shiva.b...@sewingwitch.com> ha scritto nel messaggio
news:Xns9A22913E59B...@207.46.248.16...

>I have a DLL linked to my own app that works fine when throwing from DLL to
> application. But with a customer application I get a heap corruption
> exception when the thrown exception goes out of scope in the catch clause.

> both app and DLL


> are linked against the VC6 multi-threaded debug DLL runtime.

So, this is OK.

> Any idea
> what's going wrong here?

Have you installed the latest service pack for VC6 (i.e. Service Pack 6)?
Is this SP6 installed both on your computer and on that of your customer?

Does your customer application catch exception correctly?

e.g. if the exception is derived from std::exception, you can throw on the
stack, and catch using references or const references, like:

...
catch ( const SomeException & e )
{
...
}

Moreover, did you check if your customer application code has no problem
with other heap allocations (like some buffer overrun, or some pointer that
went out of control...?)

Giovanni


Ben Voigt [C++ MVP]

unread,
Jan 14, 2008, 9:51:30 AM1/14/08
to

"Kenneth Porter" <shiva.b...@sewingwitch.com> wrote in message
news:Xns9A22913E59B...@207.46.248.16...

>I have a DLL linked to my own app that works fine when throwing from DLL to
> application. But with a customer application I get a heap corruption
> exception when the thrown exception goes out of scope in the catch clause.
> I've copied the stack below. To the best of my knowledge, both app and DLL
> are linked against the VC6 multi-threaded debug DLL runtime. Any idea
> what's going wrong here?

C++ exceptions should not be thrown across module boundaries. You should
instead catch the exception at the entry point to the DLL (not application
entry point, but each exported DLL function) and indicate the error in a
portable way. Your options are:

(1) error/status code
(2) COM exception (which really is a status code)
(3) structured exception (not recommended for user-mode applications)

>
> _CrtIsValidHeapPointer(const void * 0x09b56480) line 1697
> _free_dbg_lk(void * 0x09b56480, int -572662307) line 1044 + 9 bytes
> _free_dbg(void * 0x09b56480, int -572662307) line 1001 + 13 bytes
> operator delete(void * 0x09b56480) line 49 + 16 bytes
> MSVCRTD! exception::~exception(void) + 45 bytes
> AxisSafetyException::~AxisSafetyException() + 208 bytes
> MSVCRTD! DestructExceptionObject(struct EHExceptionRecord *,unsigned char)
> + 85 bytes
> MSVCRTD! __FrameUnwindToState + 807 bytes
> MSVCRTD! __FrameUnwindToState + 458 bytes
> MSVCRTD! __InternalCxxFrameHandler + 800 bytes
> MSVCRTD! __InternalCxxFrameHandler + 227 bytes
> MSVCRTD! __CxxFrameHandler + 44 bytes
> NTDLL! 7c9037bf()
> NTDLL! 7c90378b()
> NTDLL! 7c90eafa()
> MSVCRTD! _CxxThrowException@8 + 57 bytes

It looks like your DLL and the application are using different memory
managers.

Out of curiosity, is the customer's catch block using catch-by-value or
catch-by-reference?


Matt Osborn

unread,
Jan 15, 2008, 8:41:15 AM1/15/08
to
> C++ exceptions should not be thrown across module boundaries. You should
> instead catch the exception at the entry point to the DLL (not application
> entry point, but each exported DLL function) and indicate the error in a
> portable way. Your options are:
>
> (1) error/status code
> (2) COM exception (which really is a status code)
> (3) structured exception (not recommended for user-mode applications)

If this is true, then it is virtually impossible to intantiate an instance
of a class across a DLL boundary. How does the constructor report an error
without resorting to two stage construction techniques?


Doug Harrison [MVP]

unread,
Jan 15, 2008, 11:51:08 AM1/15/08
to
On Tue, 15 Jan 2008 07:41:15 -0600, "Matt Osborn" <a@b.c> wrote:

>If this is true, then it is virtually impossible to intantiate an instance
>of a class across a DLL boundary. How does the constructor report an error
>without resorting to two stage construction techniques?

You throw an exception, of course. In order to share classes between
modules, throw C++ exceptions between modules, etc. you have to treat the
situation as equivalent to static linking in that you must link the
participating modules to the same CRT DLL, use the same compiler and
compiler options, etc. Even that's worded a little strong, because not all
compiler options are relevant to this, but if you adhere to these rules,
the remaining problems will concern template static data (gets instantiated
in every module that uses the template) and a couple of really obscure
things.

--
Doug Harrison
Visual C++ MVP

Alexander Nickolov

unread,
Jan 15, 2008, 7:40:07 PM1/15/08
to
> If this is true, then it is virtually impossible to intantiate an instance
> of a class across a DLL boundary. <snip>

Just very very hard to do right. One more argument why you should
never do it. For an easier way - check out COM. It cuts through
your design in a very invasive manner, but all guessing is out of the
way and you end up with clean separation along your DLL boundaries.

--
=====================================
Alexander Nickolov
Microsoft MVP [VC], MCSD
email: agnic...@mvps.org
MVP VC FAQ: http://vcfaq.mvps.org
=====================================

"Matt Osborn" <a@b.c> wrote in message
news:%23VTlex3...@TK2MSFTNGP04.phx.gbl...

Doug Harrison [MVP]

unread,
Jan 15, 2008, 10:34:53 PM1/15/08
to

There was a VC5/6 bug that caused double-destruction of exception objects
under certain circumstances. Here's an example of the sort of code that
elicits it:

http://groups.google.com/group/microsoft.public.vc.language/msg/ff9d579765bed5b7

Ben Voigt [C++ MVP]

unread,
Jan 16, 2008, 10:49:51 AM1/16/08
to

"Matt Osborn" <a@b.c> wrote in message
news:%23VTlex3...@TK2MSFTNGP04.phx.gbl...

Using two return values (one must actually be an out parameter). One
indicates success or failure of instantiation, the other returns the pointer
to the new object.

See for example CoCreateInstance.


Kenneth Porter

unread,
Jan 18, 2008, 12:29:18 AM1/18/08
to
"Doug Harrison [MVP]" <d...@mvps.org> wrote in
news:8muqo399o17r2cek2...@4ax.com:

> There was a VC5/6 bug that caused double-destruction of exception
> objects under certain circumstances. Here's an example of the sort of
> code that elicits it:
>
> http://groups.google.com/group/microsoft.public.vc.language/msg/ff9d579
> 765bed5b7

Thanks, that looks a lot like what I'm seeing. I'll try to reproduce that.

Kenneth Porter

unread,
Jan 18, 2008, 12:28:50 AM1/18/08
to
"Ben Voigt [C++ MVP]" <r...@nospam.nospam> wrote in news:OAEgBzrVIHA.1132
@TK2MSFTNGP06.phx.gbl:

> It looks like your DLL and the application are using different memory
> managers.
>
> Out of curiosity, is the customer's catch block using catch-by-value or
> catch-by-reference?

const reference. The customer code is designed around error codes instead
of exceptions, so there's an adapter class that passes the exceptions to a
dispatcher routine that issues a try { throw; } and then a series of
catches that convert each exception type to an error code. (The app dates
back to before exceptions were commonplace.)

As a workaround, I'm using an RTTI-based dispatcher. Instead of try/catch,
it does an if/else sequence that attempts a dynamic_cast to pointer on each
exception type, then returns the error code when the cast returns non-null.

Kenneth Porter

unread,
Jan 18, 2008, 7:28:01 PM1/18/08
to
Kenneth Porter <shiva.b...@sewingwitch.com> wrote in
news:Xns9A28DA977A6...@207.46.248.16:

> "Doug Harrison [MVP]" <d...@mvps.org> wrote in
> news:8muqo399o17r2cek2...@4ax.com:
>
>> There was a VC5/6 bug that caused double-destruction of exception
>> objects under certain circumstances. Here's an example of the sort of
>> code that elicits it:
>>
>> http://groups.google.com/group/microsoft.public.vc.language/msg/ff9d57

>> 9 765bed5b7

>
> Thanks, that looks a lot like what I'm seeing. I'll try to reproduce
> that.

That's it! I just tried the code in the linked message (with and without
const in the catch) and I get the double-destruction. So no DLL is
necessary.

My compiler version:

Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for
80x86

For reference, here's the complete program from the linked message.
Compile with "cl -GX" and run the result.

From the linked message:

You can use the one below. Compiled with "cl -GX k1.cpp" under VC6, the
program output is:

D>k1
ctor: 0012FF6C
dtor: 0012FF6C
dtor: 0012FF6C

#include <iostream>
using namespace std;

struct A
{
A() { cout << "ctor: " << this << endl; }
A(const A&) { cout << "copy ctor: " << this << endl; }
~A() { cout << "dtor: " << this << endl; }

};

void main()
{
try
{
throw A();
}
catch (A&)
{
try
{
throw;
}
catch (A&)
{
}
}

}

0 new messages