Archived

This topic is now archived and is closed to further replies.

gimp

[STL] list.clear() across DLL boundry causes exception

Recommended Posts

Initially this might have looked like a typicall ''this is my first attempt as a DLL'' type question, but dammit I''ve been working with DLL for ~ 2 years, these particular DLL!. Ok, this is a little long but I didn''t want to miss anything. My DLL''s have an Allocate\Deallocate function that return a pointer to the class in them. I use that pointer to access the member functions of the class in the DLL (I setup the pointer to be managed by a singeton in the EXE). The DLL. It collects input from window events and stores them in a a std::list as a bunch of simple struct like classes(public data). All very simple so far. When user code in the EXE, like the GUI wants some events, it gets some itr''s from the DLL reads the events etc. When all the user code that needs this input are over I call an .ClearEvents() method on my class that in turn calls m_Events.clear(); on the stored events. ==Exception== Now, the code I call from the EXE is just a member function on the class, called by following the pointer. The deallocation should be happening IN the DLL. I don''t get it... I''ve been on this one for about 3 days now. Problem is that I can''t even think of any other way of working around the problem.
  
CInput::GetInstance().ClearEvents();
~~
std::list<CInputEvent>	m_Events;
~~
void CInput::ClearEvents(void)
{
	m_Events.clear();
}
  
I get the exception in dbgheap.c right at the end of the section that talks about checking for pointers from other heaps. ntdll.dll!77f7f570() ntdll.dll!77f67dc6() kernel32.dll!77e6c936() Game.exe!_CrtIsValidHeapPointer(const void * pUserData=0x00e58fb8) Line 1807 Game.exe!_free_dbg(void * pUserData=0x00e58fb8, int nBlockUse=1) Line 1132 + 0x9 Game.exe!operator delete(void * pUserData=0x00e58fb8) Line 53 + 0x10 Game.exe!std::allocator >::_Node>::deallocate(std::_List_nod >::_Node * _Ptr=0x00e58fb8, unsigned int __formal=1) Line 122 + 0x9 Game.exe!std::list >::erase(std::list >::iterator _Where={...}) Line 588 Game.exe!std::list >::erase(std::list >::iterator _First={...}, std::list >::iterator _Last={...}) Line 596 + 0x23 Game.exe!std::list >::clear() Line 603 Game.exe!CInput::ClearEvents() Line 46 Game.exe!CGame:rocessInput() Line 103 Game.exe!CGame::Execute() Line 47 Game.exe!CScheduler::Execute() Line 61 + 0x23 Game.exe!main(int argc=1, char * * argv=0x00a81560) Line 150 Game.exe!WinMain(HINSTANCE__ * a_Instance=0x00400000, HINSTANCE__ * a_PreviousInstance=0x00000000, char * a_Args=0x00141f13, int a_CmdShow=1) Line 29 + 0x12 Game.exe!WinMainCRTStartup() Line 251 + 0x32 kernel32.dll!77e7eb69() Help? Anyone? Chris Brodie http:\\fourth.flipcode.com

Share this post


Link to post
Share on other sites
Errrr...

Oh, I don''t know if it matters but My DLL class CNativeInput is derived from CInput. CInput is in a static lib. That shouldn''t matter right?

I just check the heap for another of my DLL''s, a function that DOES live in a DLL, not a static lib, The OpenGL DLL. The stack looks like this:

OpenGL.dll!COpenGL::COpenGL() Line 48
OpenGL.dll!Allocate() Line 31 + 0x27
Game.exe!CComponent::CComponent(const std::basic_string,std::allocator > & a_Name={...}) Line 70 + 0x8
Game.exe!main(int argc=1, char * * argv=0x00a81560) Line 106 + 0x38
Game.exe!WinMain(HINSTANCE__ * a_Instance=0x00400000, HINSTANCE__ * a_PreviousInstance=0x00000000, char * a_Args=0x00141f13, int a_CmdShow=1) Line 29 + 0x12
Game.exe!WinMainCRTStartup() Line 251 + 0x32
kernel32.dll!77e7eb69()


See how the code I step in to shows the ''Name'' OpenGL.DLL???

Maybe it''s the fact that My code is in a static libe thats it''s getting bound on to the EXE rather than the DLL???

I''m missing something here...

This is how My Game OS is structured:

Static Lib CRenderer
DLL COpenGLRenderer

A config file says ''OpenGL'' So I load the DLL and shove the pointerto the class allocated in the DLL in to a singleton. That way I can call generic CRenderer::GetInstance(). type call''s all through my code. I just use the static lib to hold the ''template''. I also use the static lib for ''common'' code that is shared by all derived classes. Like an FPS counter would be common no matter the actual API, D3D of OGL, so this goes in the static lib and is linked in by both.

Is there some grand flaw in my logic here? Have I just solved my problem as I typed again?

(You don''t know how many posts I just don''t post as I work them out as I type the question)

???



Chris Brodie
http:\\fourth.flipcode.com

Share this post


Link to post
Share on other sites
No. It''s all single threaded, exe, dll''s etc. It''s cool anyway. I was right above, I talked myself in to an answer. I just moved all the code from the static lib in to the actual DLL, now the allocations are being performed inside the address space of the DLL and it works a treat.



Chris Brodie
http:\\fourth.flipcode.com

Share this post


Link to post
Share on other sites
The STL can''t be used in Win32 DLLs very easily. Here''s the Microsoft explanation out of MSDN: http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q172396&

Templates and static data members that aren''t "in sync" across executable image boundaries can cause access violations, corrupted data, you name it.

Basically, you can''t export STL class members out of a DLL.

Came across this particular nastiness because of a weird destructor bug: anytime a class in my DLL destructed, the entire process came down with it in an access violation. Very annoying. / =

Share this post


Link to post
Share on other sites
Okay, wait, I was all happy with my answer till it worked for you. ( =

You basically wrapped the STL functions you needed with methods, right? Didn''t expose the STL members in the class? Or did you expose the whole class (_declspec(export))?

I was having this destructor problem where my DLL would throw an exception during the destruction of one of the classes in it... after messing around with multi-screen debugging (argh), I saw it was in the destructor for the STL member... found the MSDN article, threw my hands up ''cuz I needed to export the STL member for my functionality, and that was that -- that class went into a static library, out of the DLL. Am I wrong here? It seemed like whenever I put an STL member in a class that was exported from the DLL, it would do the destructor-crash thing... is that because I was exporting the whole class, not individual methods/members? Argh again.

Share this post


Link to post
Share on other sites
Actually I don''t expoert anything from my DLL''s except for two functions that are always the same


  
EXPORT CInterface* Allocate(void)
{
return new CNative;
}


EXPORT void Deallocate(CInterface* a_Interface)
{
delete a_Interface;
}


The interesting thing about this is that first of all you get a pointer to the whole class. You can call ANY public function on it and not have to worry about exporting it. Second, your not passing around items that are static which I''ve had problems with. Allocate in the DLL''s heap, then pass the pointer to the EXE.

There might be a potential memory leak by assuming that the user will remember to call ''Deallocate()'' on the dll''s class. No biggie. I just wrapped it in a class that is used in the exe to manage the life time of the exported class. Sort of the way a smart pointer works only using Allocate() \ Deallocate() rather than new\delete behind the scened.

One last thing. Never use static''s across DLL boundries. You''ll just be buying in to a world of pain as the DLL and EXE will maintain their own copies of the static. To get the same effect, use a singleton pattern that allows you to ''give'' the singleto a pointer in the exe. Then use Allocate() to force allocation in the DLL, pump the pointer in to the singleton, then use it. My whole engine is based around this concept.

This idea was given to me by null and void if I remember correctly about a year ago

My error above is still odd, I think that since i inherit from a static lib included in both the exe\dll the exe was preferring to the use function addresses it know about rather than relying on the dll, cause the exe was calling the static lib functions of a class allocated in a DLL, hence my pain... I didn''t get it till I pasted out the stack traces...

Email me if you want my source files.

HTH



Chris Brodie
http:\\fourth.flipcode.com

Share this post


Link to post
Share on other sites
Hate to torque you, but we export STL members in a utility class. We get this warning about the base class not being declared as exported, but it''s never hurt us (yet). We''ve move away from doing this because the warning is spooky, but we haven''t had a problem yet.

Share this post


Link to post
Share on other sites
Just you wait. It crept up and bit me out of nowhere.

The static bit I knew about... and I guess my problem was I was exporting the whole class (methods, members), not just select methods. Any advantage (besides being able to use the STL) to only exporting the methods?

That smart pointer thing is nice... the singleton pattern I''m already using for some key systems (like the InputSubsystem)... I think you''re right about the static library... the EXE is preferring it''s own version of the function calls, and this mucks the memory space.

I guess it''s time to do some experimenting... thanks! ( =

Share this post


Link to post
Share on other sites