Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2010-10

TProcess.Free - three exceptions in ntdll.dll - only *sometimes*

5 messages · 2 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Bernd Kreuss

Hi,

has anybody ever had the problem of TProcess.Free causing three exceptions in in ntdll.dll?

C0000005 at 7C928FEA in C:\WINDOWS\system32\ntdll.dll

7C928FEA seems to be RtlpWaitForCriticalSection() somewhere deep inside the windows kernel.

The first two happen almost immediately and the third one a few seconds later. I narrowed it down to TProcess.CloseOutput(), CloseInput() and CloseStderr() and if I create the process with poStderrToOutPut there will only be two exceptions instead of three.

At the time this happens the process is already terminated because I sent it its quit command via its input and then WaitOnExit() and it will terminate orderly. Nobody should be reading or writing to these pipes anymore.

Is there any alternative way to close the stdio? My only workaround at the moment is to never free the TProcess at all and simply hope that it won't crash when the dll is unloaded (it is all residing inside a dll that is loaded and unloaded during runtime). Most of the time it won't crash this way, but unfortunately not always.

Bernd

Bernd Kreuss
to Bernd Kreuss
Bernd Kreuss wrote 6 lines
Hi, has anybody ever had the problem of TProcess.Free causing three exceptions in in ntdll.dll? C0000005 at 7C928FEA in C:\WINDOWS\system32\ntdll.dll

Just for the record: It was not TProcess and also not the streams, at least not directly: After further experimenting and simplifying the dll until it finally consisted of nothing more than only two functions that would create and destroy some dummy object without any functionality I still saw this exception immediately when freeing the object and the same exception again *after* the host app had unloaded my dll.

I have now put the cmem unit into my uses (I always only saw this mentioned in combination with the cthreads for *ix, never thought that it was usable on win32 too) and the exceptions while freeing obects seem to have all gone away. However I still see exactly one such exception *after* unloading the dll but the host app seems to be able to catch it without crashing.

(the host app is unfortunately a commercial closed source application and probably written in C++ [at least it is definitely not from any borland or compatible compiler since FPU exceptions are masked])

Bernd

Bernd Kreuss
to Bernd Kreuss: has anybody ever had the problem of TProcess.Free causing three exceptions in in…
Bernd Kreuss wrote
C0000005 at 7C928FEA in C:\WINDOWS\system32\ntdll.dll 7C928FEA seems to be RtlpWaitForCriticalSection() somewhere deep inside the windows kernel.

I see this error message now exactly once, immediately *after* the DLL has been unloaded by the host application.

I'm just looking at the code below (from fpc 2.5.1 trunk, rtl/win/syswin.inc) and I wonder whether this usage of the critical section functions might eventually be related to this? (I am still trying to completely understand this and try to understand why it is allowed or needed to put these init/done calls in two separate calls of dllmain, especially this sudden exit in DLL_PROCESS_DETACH caught my eye:

function Dll_entry{$ifdef FPC_HAS_INDIRECT_MAIN_INFORMATION}(const info
: TEntryInformation){$endif FPC_HAS_INDIRECT_MAIN_INFORMATION} :
longbool; [public,alias:'_FPC_DLL_Entry'];
  begin
{$ifdef FPC_HAS_INDIRECT_MAIN_INFORMATION}
     EntryInformation:=info;e
{$endif FPC_HAS_INDIRECT_MAIN_INFORMATION}
     IsLibrary:=true;
     Dll_entry:=false;
     case DLLreason of
       DLL_PROCESS_ATTACH :
         begin
           WinInitCriticalSection(AttachingThread);
           MainThreadIdWin32 := Win32GetCurrentThreadId;
           If SetJmp(DLLBuf) = 0 then
             begin
{$ifdef FPC_HAS_INDIRECT_MAIN_INFORMATION}
               EntryInformation.PascalMain();
{$else FPC_HAS_INDIRECT_MAIN_INFORMATION}
               PascalMain;
{$endif FPC_HAS_INDIRECT_MAIN_INFORMATION}
               Dll_entry:=true;
             end
           else
             Dll_entry:=DLLExitOK;
         end;
       DLL_THREAD_ATTACH :
         begin
           inclocked(Thread_count);
           WinEnterCriticalSection(AttachingThread);
           if Win32GetCurrentThreadId  MainThreadIdWin32 then
           begin
             { Allocate Threadvars  }
             SysAllocateThreadVars;

{ NS : no idea what is correct to pass here - pass dummy value for now }
{ passing a dummy is ok, the correct value is read from the coff header of SysInstance (FK) }
InitThread($1000000); { Assume everything is idempotent there, as the thread could have been created with BeginThread... }

           end;
           if assigned(Dll_Thread_Attach_Hook) then
             Dll_Thread_Attach_Hook(DllParam);
           Dll_entry:=true; { return value is ignored }
           WinLeaveCriticalSection(AttachingThread);
        end;
       DLL_THREAD_DETACH :
         begin
           declocked(Thread_count);
           if assigned(Dll_Thread_Detach_Hook) then
             Dll_Thread_Detach_Hook(DllParam);
           { Release Threadvars }
           if Win32GetCurrentThreadIdMainThreadIdWin32 then
             DoneThread; { Assume everything is idempotent there }
           Dll_entry:=true; { return value is ignored }
         end;
       DLL_PROCESS_DETACH :
         begin
           Dll_entry:=true; { return value is ignored }
		   if MainThreadIDWin32=0 then // already been here.
		     exit;
           If SetJmp(DLLBuf) = 0 then
             FPC_Do_Exit;
           if assigned(Dll_Process_Detach_Hook) then
             Dll_Process_Detach_Hook(DllParam);
           DoneThread;
           { Free TLS resources used by ThreadVars }
           SysFiniMultiThreading;
           WinDoneCriticalSection(AttachingThread);
		   MainThreadIDWin32:=0;
         end;
     end;
  end;
Bernd Kreuss
to Bernd Kreuss
Bernd Kreuss wrote
I see this error message now exactly once, immediately *after* the DLL has been unloaded by the host application.

Correction: I see it after my log output within my finalization section, it might still be in the final stages of DLL_PROCESS_DETACH.

Where exactly is the finalization (the finalization section in my source code) hooked into? is it Dll_Process_Detach_Hook?

Sven Barth
to Bernd Kreuss
Bernd Kreuss wrote 9 lines
On 05.10.2010 20:55, Bernd Kreuss wrote: > I see this error message now exactly once, immediately *after* the DLL > has been unloaded by the host application. Correction: I see it after my log output within my finalization section, it might still be in the final stages of DLL_PROCESS_DETACH. Where exactly is the finalization (the finalization section in my source code) hooked into? is it Dll_Process_Detach_Hook?

If I remember correctly, yes. Search for "fpc_do_exit" in the rtl/ directory (and the methods called from there).

On a sidenote: The critical section should not be necessary, because DllMain is called serialized by the OS (according to http://blogs.msdn.com/b/oldnewthing/archive/2004/01/28/63880.aspx ).

Regards,
Sven