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

d-bugmail at puremagic.com d-bugmail at puremagic.com
Sat Jul 21 10:26:26 PDT 2007


http://d.puremagic.com/issues/show_bug.cgi?id=1360





------- Comment #2 from wqeqweuqy at hotmail.com  2007-07-21 12:26 -------
(In reply to comment #1)
> d-bugmail at puremagic.com wrote:
> > 
> > If an external process trys to CreateRemoteThread the current process (to
> > inject a DLL in this case) the gcx stack scanning code fails in
> > GetThreadContext().
> 
> I'm not sure there's anything that can be done about this.  The stack 
> scanning routine only calls GetThreadContext on threads it knows about 
> (ie. D threads), so it's unlikely GetThreadContext is interacting 
> directly with the injected thread.  More likely, and more troubling, is 
> that injecting a thread is screwing up the application somehow and 
> causing it to fail.  If I had to guess, I'd say that the injected thread 
> was using debug routines (specifically, SuspendThread and ResumeThread) 
> at the same time a collection cycle was occurring, and it resumed a 
> thread that was supposed to be suspended for scanning or something like 
> that.
> 
> More remote is that the process of injecting a thread is screwing 
> something up.  From the docs on CreateRemoteThread:
> 
>      there are several side effects to using this technique:
> 
>      * It converts single-threaded applications into multi-threaded
>        applications.
>      * It changes the timing and memory layout of the process.
>      * It results in a call to the entry point of each DLL in the
>        process.
> 
> Normally, I'd think these should all be fine, but given the error, I'm 
> wondering what the second clause implies.
> 
> > GetLastError() returns ERROR_GEN_FAILURE and the code hard exists via a HLT
> > instruction.
> 
> Unfortunately, this isn't terribly useful.  Near as I can tell, 
> ERROR_GEN_FAILURE just indicates a general failure condition.  The 
> actual text description is "a device attached to the system is not 
> functioning."
> 
> > Seems a few anti virus/spyware utilities use this injection method, so its
> > likely to be a problem.
> 
> A further comment on the function:
> 
>      Another common use of this function is to inject a thread into a
>      process to query heap or other process information. This can cause
>      the same side effects mentioned in the previous paragraph. Also, the
>      application can deadlock if the thread attempts to obtain ownership
>      of locks that another thread is using.
> 
> This doesn't sound terribly encouraging.  Is the error reproducible? 
> I'm curious if it's a timing issue.
> 
> 
> Sean
> 

I dont think its a race condition with the thread being created during a
collection cycle, it happens everytime a GC collect is run (with the exception
below). 

This bug had been affecting one of my users for a long time and i could never
figure out what on his PC was causing it to fail (ended up being some anti
spyware stuff injecting DLLs like this somewhere along the line). By chance,
someone had sent me some loader and it was producing the same symptoms that the
one user was having.

Long story short: This loader called CreateProcess with CREATE_SUSPENDED flag,
injected its DLL into the process with CreateRemoteThread, and hit resume. 

I ended up copying the thread enumeration code out of the gcx function:

Thread[] threads = Thread.getAll();
for (uint n = 0; n < threads.length; n++)
{
    Thread t = threads[n];
    if (t && t.getState() == Thread.TS.RUNNING)
    {
        display.printf("Thread[%d]: Thread.isSelf() = %d\n", n, t.isSelf());
        CONTEXT context;
        context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
        if (!GetThreadContext(t.hdl, &context))
            display.printf("GetThreadContext: handle=%08x id=%08x error=%d\n",
t.hdl, GetCurrentThreadId(), GetLastError());
    }
}

produces the output:

Thread[0]: Thread.isSelf() = 0
GetThreadContext: handle=0120 id=00000D50 error=31 (ERROR_GEN_FAILURE)

I should be doing something like GetThreadId(0x0120) here but its vista only,
and i'm on XPSP2. Checking with a debugger shows the main thread is 0xd50.
Assuming the isSelf() isnt failing for another reason, its possible the thread
the GC consumed as "Main" thread at gc_init is pointing to the
CreateRemoteThread one or something. 

I also tried to run a collection cycle in the D programs DLLmain and it worked
ok. Im not sure if thats just because the stack scanning code wasnt hit, due to
there being nothing allocated, or from the CreateRemoteThread thread being
active still or something.


-- 



More information about the Digitalmars-d-bugs mailing list