Access violation exception at end of catch block

Started by
7 comments, last by Prune 14 years, 10 months ago
I load some dll-based modules in a try{} and then I have some catch{} blocks. Throwing a test exception from a virtual function in a class in the dll (the class is not exported, just a function that creates a new object instance from the class is exported), the exception is caught and the code in the catch{} executes, right after dtors of the locals created in the try{} block, including the dtor of the objects that holds the dll handles and so the dlls are freed. However, (stepping it in Debug mode) it gets to the closing } of the catch{}, when I execute that closing statement I get "First-chance exception at 0x68ad2377 (msvcr90d.dll) in dev_cored.exe: 0xC0000005: Access violation reading location 0x02764ed0." I can't see where the exception is from due to the "Frames below may be incorrect and/or missing" (the debugger shows the next statement arrow at the caller of the virtual function mentioned above that throws the test exception, which makes no sense as that function is only called in the main thread, so I assume that's due to the corrupted frames). I have not the slightest idea how to debug this, so I'm really hoping someone can help me.
"But who prays for Satan? Who, in eighteen centuries, has had the common humanity to pray for the one sinner that needed it most?" --Mark Twain

~~~~~~~~~~~~~~~Looking for a high-performance, easy to use, and lightweight math library? http://www.cmldev.net/ (note: I'm not associated with that project; just a user)
Advertisement
Sounds to me like accessing deleted memory, or something similar.

Of course if you want an actual answer instead of just idle speculation, you'll have to post the code [wink]

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

You have to take care when throwing exceptions across DLL boundaries. Memory allocated in the DLL might not even use the same heap as your application, for example.

You must also ensure that both the DLL and application were compiled with the same compiler, under the same compiler settings. Otherwise, if your exception contains something like a std::string, you could very easily run into ODR violations.

IMO it's better to just avoid it altogether - don't throw exceptions across DLL boundaries.
NextWar: The Quest for Earth available now for Windows Phone 7.
Everything is compiled with the same compiler and settings.

The exception is just an int. Catching by reference or by value makes no difference to this issue.

I'm running 32-bit builds on on 64-bit Vista, if it matters, but from what I remember the same thing happened on 32-bit XP. I'm using SDL so that overrides my main with its main and has some stuff registered with atexit. But I don't think this has anything to do with it either. I'm just using it for event handling.

I can't understand how the exception can be generated, considering the module objects have been destroyed and the dlls unloaded (I know as when I Debug-stepped through the code, it goes through all the right destructors). It happens right at the } of the catch block, and there's nothing in the catch other than cout << '!' << endl; !!

I don't know if it could have anything to do with the virtual mechanism. I cannot test throwing from a non-virtual functions, as the modules in the DLLs are derived from a Module abstract class which is the only thing the main application knows (since new dlls get added to the application over time as it's running and it dynamically loads them).

I can post code but it's kind of large and would be hard to trim without knowing what part I can safely omit given I'm not sure what could be causing the problem.
"But who prays for Satan? Who, in eighteen centuries, has had the common humanity to pray for the one sinner that needed it most?" --Mark Twain

~~~~~~~~~~~~~~~Looking for a high-performance, easy to use, and lightweight math library? http://www.cmldev.net/ (note: I'm not associated with that project; just a user)
I also tried enabling structured exceptions with /EHa and still no change.

If I break on the second exception (after enabling breaking on all exceptions in the Visual Studio debugger), in "location" field in threads for the main thread it shows "msvcr90d.dll!__DestructExceptionObject(EHExceptionRecord * pExcept=0x0017ee4c, unsigned char fThrowNotAllowed=0) Line 1803 + 0xf bytes"
"But who prays for Satan? Who, in eighteen centuries, has had the common humanity to pray for the one sinner that needed it most?" --Mark Twain

~~~~~~~~~~~~~~~Looking for a high-performance, easy to use, and lightweight math library? http://www.cmldev.net/ (note: I'm not associated with that project; just a user)
A very simplified structure of the program:

shared header:
class Module{public:	virtual void Foo(void) = 0;};

dll:
class SomeSpecificModule : public Module{public:	virtual void Foo(void);};void SomeSpecificModule::Foo(void){	throw 1;}extern "C" __declspec(dllexport) Module* GetModule(){	return new SomeSpecificModule;}

program:
typedef ptrGetModule* (*GetModule)();int main(void){	HANDLE hMod = LoadLibrary("SomeSpecificModule.dll");	ptrGetModule GetModule = (ptrGetModule)GetProcAddress(hMod, "GetModule");	try	{		Module *d = GetModule();		d->Foo();	}	catch (...)	{		cout << '!' << endl;	}	return 0;}
"But who prays for Satan? Who, in eighteen centuries, has had the common humanity to pray for the one sinner that needed it most?" --Mark Twain

~~~~~~~~~~~~~~~Looking for a high-performance, easy to use, and lightweight math library? http://www.cmldev.net/ (note: I'm not associated with that project; just a user)
The kind of exception you're getting isn't the same as a C++ exception. In short, you're getting told by the OS that you did something wrong.

I'm afraid that without code there's not much we can do besides guess randomly. Feel free to post as much code as needed; if it's really that big, drop me a PM and I can arrange to have it hosted on my GDNet web space for download.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

I agree, it is probably not a C++ exception, it's most likely a double deletion, dereferencing a null, or acting on deleted memory. But with only this much to go on, that's about as much as I can guess.

Since you're using VS2009, try throwing a breakpoint in the destructor of every object that goes out of scope at the end of your catch block, and see if anything turns up. I'd particularly look at your DLL wrappers and any components they might have with custom destructors. Maybe two of them refer to the same resource without shared ownership semantics?

I took the dll handle wrapper object out of the try{} scope and now thing seem to work. It looks like Windows tries to do destruction on the exception (even when I just throw an int) at the end of the catch{} and if the dll gets unloaded at the end of the try{}, then I guess it causes a problem (although the exception still gets caught correctly and I can print its contents).

Although I have found the workaround, the downside is that now I need a nesting try{} block around the first one to catch exceptions thrown by the dll handle wrapper itself. That makes for three nested try{} blocks, as I already have an outer one for the logger object, as I log all exceptions, other than those generated by the logger itself, which just go to cerr. So now I've ended up with code like
try{	Log log(...);	try	{		vector<shared_ptr<Library>> libs;		try		{			// Everything else		}		catch (exception const &e)		{			FTL(log, e.what());		}		catch (char const s[])		{			FTL(log, s);		}		catch (...)		{			FTL(log, "Unknown exception");		}	}	catch (exception const &e)	{		FTL(log, e.what());	}	catch (char const s[])	{		FTL(log, s);	}	catch (...)	{		FTL(log, "Unknown exception");	}}catch (exception const &e){	cerr << e.what() << endl;}catch (char const s[]){	cerr << s << endl;}catch (...){	cerr << "Unknown exception" << endl;}

which is quite ugly and I'm hoping there's a less verbose way to do things.
"But who prays for Satan? Who, in eighteen centuries, has had the common humanity to pray for the one sinner that needed it most?" --Mark Twain

~~~~~~~~~~~~~~~Looking for a high-performance, easy to use, and lightweight math library? http://www.cmldev.net/ (note: I'm not associated with that project; just a user)

This topic is closed to new replies.

Advertisement