[Issue 1360] GC emits HLT when GetThreadContext fails after CreateRemoteThread.

Sean Kelly sean at f4.ca
Sun Jul 22 10:21:08 PDT 2007


d-bugmail at puremagic.com wrote:
>
> ------- Comment #4 from wqeqweuqy at hotmail.com  2007-07-21 15:58 -------
> - The "target" application is in C++. 
> - The D code is a DLL that wraps some directx COM interfaces and hooks the
> target.
> - The problematic loader is in C++ using CreateRemoteThread with LoadLibrary.
> 
> The loader is injecting the D DLL into the target application. D DLL's Dllmain
> calls gc_init, m_init etc for PROCCESS_ATTACH.

Okay that explains it.  Since the injected thread is loading the DLL, it 
is the one which calls PROCESS_ATTACH, which in turn creates a proxy 
object for the injected thread instead of the main thread. 
Unfortunately, I don't know of a way to make this work automatically. 
Basically, you need to change the thread handle (Thread.hdl) to be the 
handle of the main thread before the injected thread exits.

> The thing is, using the "madChook" library to inject the dll instead, through
> its version of "CreateProcessEx" or its system wide "inject on process creation
> through a kernel driver" method works perfectly fine. AFAIK both his methods
> inject before the target program's entry point is called too. 

madChook likely uses a method that tricks the main thread into calling 
PROCESS_ATTACH.  It's been a while since I've used that lib however, so 
I don't know offhand how it's done.

> It seems like the presence of a CreateRemoteThread call alone is messing up the
> GC. Since the GC worked fine, using the madChook method, on that one user's PC
> after uninstalling everything that could possibly be injecting unrelated dlls
> with CreateRemoteThread. Yahoo messenger, Norton etc. 
> 
> It might work better to do a seperate scan of GetCurrentThread() instead of
> having a resident non-D Main thread, but that leads to problems if you dont run
> a collection cycle before D functions returns to non-D-space.

Well, a proxy object for the main thread must exist for other reasons 
(for Thread.getThis to work, for example), so while that approach would 
likely fix garbage collection, the app could still segfault if an 
unknown thread (the main thread in this case) calls certain thread routines.

What I'm probably going to do for Tango is provide routines to register 
and de-register proxy objects for 'foreign' threads.  The injected 
thread, then, would have to de-register itself and register the main 
thread before exiting.  I imagine it must be possible to get the thread 
handle of the main process thread using debug routines?  Something 
similar could be done for Phobos as well.

> A simple solution for DLLs might be to manually initalize what the GC uses as
> the main thread somewhere along the line (if needed). And allow it to fall back
> on FullCollectNoStack() if theres no Main thread registered. I'm not sure if
> this will result in leaks or not though. 
> 
> Also, the behavior on that one users PC makes it seem like it could be
> something unrelated to initialization that is breaking things too. 
> 
> Seems like this is going to be messy to deal with haha.

I like the above approach best, assuming it's possible.  With it, 
scanning wouldn't have to change at all, but non-D threads that wanted 
to use GCed memory would be responsible for letting the D runtime know 
about them.


Sean


More information about the Digitalmars-d-bugs mailing list