I got lost, and fast!
When I build in debug mode, the access violation occurs when ROOT attempts to access memory location 0xcdcdcdcd - the value the debugging libraries fill all uninitalized variables. In short – ROOT is trying to access some uninitalized memory (it could also be memory that has been previously deleted).
Here is the stack dump when it happens:
[code] msvcr80d.dll!strlen(unsigned char * buf=0xcccccccc) Line 69 Asm
libCore.dll!TString::TString(const char * cs=0xcdcdcdcd) Line 284 + 0xf bytes C++
libCore.dll!TCint::AutoLoadCallback(const char * cls=0x0021f268, const char * lib=0x044635a0) Line 1154 + 0x30 bytes C++
libCore.dll!TCint_AutoLoadCallback(char * c=0x00e4c2e0, char * l=0x044635a0) Line 79 + 0x1c bytes C++
libCint.dll!G__class_autoloading(int tagnum=861) Line 427 + 0x1b bytes C++
libCint.dll!G__defined_tagname(const char * tagname=0x02eac058, int noerror=2) Line 578 + 0x9 bytes C++
libCore.dll!TCint::CheckClassInfo(const char * name=0x02eac058) Line 647 + 0xb bytes C++
libCore.dll!TCint::SetClassInfo(TClass * cl=0x02eabf48, bool reload=true) Line 570 + 0x29 bytes C++
libWin32gdk.dll!TGWin32InterpreterProxy::SetClassInfo(TClass * cl=0x02eabf48, bool reload=true) Line 65 + 0x1bd bytes C++
libCore.dll!TClass::SetUnloaded() Line 3303 + 0x22 bytes C++
libCore.dll!ROOT::RemoveClass(const char * cname=0x10065d34) Line 532 C++
libCore.dll!ROOT::TDefaultInitBehavior::Unregister(const char * classname=0x10065d34) Line 216 + 0x9 bytes C++
libCore.dll!ROOT::TGenericClassInfo::~TGenericClassInfo() Line 176 + 0x2b bytes C++
PyROOT::ROOT::GenerateInitInstance'::2’::`dynamic atexit destructor for ‘instance’’() + 0xd bytes C++
libPyROOT.dll!_CRT_INIT(void * hDllHandle=0x10000000, unsigned long dwReason=0, void * lpreserved=0x00000001) Line 417 C
libPyROOT.dll!__DllMainCRTStartup(void * hDllHandle=0x10000000, unsigned long dwReason=0, void * lpreserved=0x00000001) Line 509 + 0x11 bytes C
libPyROOT.dll!_DllMainCRTStartup(void * hDllHandle=0x10000000, unsigned long dwReason=0, void * lpreserved=0x00000001) Line 459 + 0x11 bytes C[/code]
I stepped around with the debugger. The line that causes the problems is 1154 in TCINT.cxx, I think:
TString deplibs = gInterpreter->GetClassSharedLibs(cls);
when the crash occurs cls is “PyROOT”. Also, gInterpreter has been changed to be a TWin32interpreterproxy guy, and it is what returns the uninitalized memory value, which causes TString to barf, and ROOT to crash.
Now, moving into the realm of shear speculation, I tried to follow the rabbit a bit further. I’m pretty sure the following is what actually happens:
TGWin32ProxyInterpreter uses the code in the file TGWin32ProxyDefs, RETURN_METHOD_ARG1 to execute the call back onto the (possibly) main thread of GetClassSharedLibs
It creates its tmp object (which I see), and fills “ret” with cdcdcdcd as it is uninitalized (tsk tsk).
It uses ForwardCallBack in order to send a mesage using the windows message pump to the main thread (this can be found in TGWin32ProxyBase).
PostThreadMessage attempts to post the message 5 times. It fails all five times and returns false.
The RETURN_METHOD_ARG1 code returns the “ret” – which wasn’t changed because the call never completed – and so cdcdcdcd is returned.
I didn’t look at GetLastError for PostThreadMessage, but I’m going to guess that it will return ERROR_INVALID_THREAD_ID – in short, the thread that the message was getting sent to was already dead.
ROOT, btw, starts up and shuts down just fine from the command line. No problems at all. I’ve also linked C++ programs against the thread libraries (and done UI stuff in those C++ programs) and not had any trouble. So, if it is as I guess, there must be some funny ordering thing going on as the shutdown occurs and, somehow, the main thread is gone.
I hope this is enough to either spot the problem or tell me what I should look at next!