Solved

DLL's and PROCESS_DETACH - Windows NT

Posted on 1998-08-10
27
589 Views
Last Modified: 2013-12-03
Windows NT 4/sp3

I have a DLL that is used to interface to one of my device drivers.

I rely on getting the DLLentry called with PROCESS_DETACH and THREAD_DETACH to clean up resources on a per-process basis.

I have now discovered that, under certain circumstances, it appears possible for a process to exit without calling my DLLentry routine. This appears to happen if a user kills a process with the WindowsNT Task Manager. Also, so a customer tells me, it can happen if a processes is being debugged or has a fatal error.

Can anyone help me out here - I need the DLL to know if a process exits/dies so that the DLL can clean up after the process (open files, resources etc).
 
0
Comment
Question by:mwright012397
  • 12
  • 6
  • 4
  • +3
27 Comments
 
LVL 22

Expert Comment

by:nietod
ID: 1413277
I don't think there is anything you are going to be able to do about this.  But these are exceptional cases.  They should not happen often or ever in the field.

The OS will do a decent job of cleaning for your.  It will close all handles (that is files, mutexes) that are closed with Closehandle().  It will release all the memory that was alocated with GlobalAlloc() or LocalAlloc().

What sort of things are you concerned about?
0
 

Author Comment

by:mwright012397
ID: 1413278
I have some memory and resources allocated to the process that must be freed.

The device driver implements numbered "ports" (somewhat like TCP ports), These are "opened" by a process and must be freed if the process does not close them itself. If not, then these "ports" become unavailable to another process.

I wondws how other systems manage this if these events are not-catchable ?



0
 

Author Comment

by:mwright012397
ID: 1413279
Unfortunately they do happen - my customer sees this problem all the time and is getting fed up with me about it ;-{

He sees the problem when debugging - if he quits the program under the debugger the DLL knows nothing about it

0
 
LVL 22

Expert Comment

by:nietod
ID: 1413280
Why would the customer be debugging?

There may be hope.  I'm doing a little rearch now.   Its on termination handling, part of structured exceptiopn handling.
0
 
LVL 22

Expert Comment

by:nietod
ID: 1413281
Nope, no hope.  But I think we can get around the problem

What are these ports and in what sense are they not freed when the DLL is closed (abnormally)?  
0
 

Author Comment

by:mwright012397
ID: 1413282
OK - background time.

I have a driver that implements "port" on a MultibusII backplane (doesn't really matter - pretend that they are TCP ports.)

User "opens a port" from a process - my dll gets the request - passes the open request to the driver - fields the reply - allocates the port to the "current" process and returns.

Normally, end user "closes the port" before exiting - dll gets erquest - passes to driver - fields reply - deallocates the port.

If the user "forgets" to close the ports - DLL gets the PROCESS_DETACH call - looks up all the ports that current process had open - closes them.

Now - if the appilcation dies in the "wrong" way - or user kill the process because something else has gone wrong - DLL never "sees" the PROCESS_DETACH - cant clean up. Result: ports opened but never closed - these ports are now unavailable.

User is debugging HIS application - not my DLL. Same result. If you "kill" the application within IDE - DLL never sees the PROCESS_DETACH.

Hope that rambling was of some use - any help appreciated here - I am really stuck for a solution.


0
 
LVL 22

Expert Comment

by:nietod
ID: 1413283
I understand more now, but what are these ports?  It take it they are not something that the OS can figure out to close, like a file or memory mapping.  (It closes those and others under these circumstances.)

Just some thoughts, When debugging can you DLL create a log of some sort that can be used to close the ports by running a clean-up program.  Perhaps it could just clean up each time it is loaded.

Or if you don't like the idea of logging the information, can the DLLdetermine what ports are open and what processes are usig them.  If a process is terminated and is using a port it could clean up by closing that port.

Another approach is to try to leave the DLL "running"  That could be done by making it a service (I'm REALLY sketchy on this stuff--could be total BULL) or a divice driver.  Another possibility is to run an application that loads the DLL and keeps the DLL loaded, perhaps it can configure the DLL and/or report its status etc.  Then when the application that uses the DLL is killed, the DLL will still remain loaded and would have a decent chance of cleaning up, if might even keep track of the processes that are attached and periodically check to see if some died, or the first EXE could have some sort of manual cleanup option.  To make this work you would probably need some data segments in the DLL that are shared between processes.  Usually when a DLL is loaded by two or more processes it is so seperate that you really can't tell that it has been loaded multiple times and would make this sort of approach useles.  But by using shared data segments (pages) you can make this sort of approach work.

Let me know if any of this sounds like it might be owrth persuing.
0
 
LVL 2

Expert Comment

by:duneram
ID: 1413284
You could catch exceptions with something like this:

LONG MyHandler (LPEXCEPTION_POINTERS *ExceptionInfo );


In the DLL setup (entrypoint)


            case DLL_PROCESS_ATTACH:
            // The DLL is being mapped into the process's address space.
                  SetUnhandledExceptionFilter
                              ((LPTOP_LEVEL_EXCEPTION_FILTER) MyHandler );
                  break;

            case DLL_PROCESS_DETACH:
                    STAMPLOG("DLL_PROCESS_DETACH")
                  // The DLL is being unmapped from the process's address
                  // space.
                  SetUnhandledExceptionFilter(NULL);  
                  break;


LONG MyHandler ( LPEXCEPTION_POINTERS *ExceptionInfo )
// Note: the structure (using) we could get the crash address...
{
   // Do some close up stuff
   return 0;
}


0
 
LVL 22

Expert Comment

by:nietod
ID: 1413285
But if the user terminates the program you don't get an exception.
0
 
LVL 1

Expert Comment

by:Arkadiy
ID: 1413286
Just a thought - can you change your driver so that your "ports" are recognized as something Windows has to close when a process exits (like events, mutexes, files etc.)
0
 
LVL 2

Expert Comment

by:duneram
ID: 1413287
That would cover the ipf/gpf cases.
0
 
LVL 22

Expert Comment

by:nietod
ID: 1413288
That would cover all the cases, but I would guess that if it could be designed that way it would have been.
0
 

Expert Comment

by:s_griffin
ID: 1413289
Why not keep a list of the process/thread IDs that are accessing the DLL and every time a new process/thread attachs check if other process/thread ids are still alive in the system using the WIN 32 calls. If it doesn't then tidy it up. ?
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
LVL 22

Expert Comment

by:nietod
ID: 1413290
The problem is that if only one process uses the DLL, it will be unloaded when the process is killed.   However, look at the suggestion I made on August 10th at 8:24.
0
 

Author Comment

by:mwright012397
ID: 1413291
Thanks for all the comments - I have been away for a day and I will have to catch up.

I still don't understand why this doesn't just "work". Why NT does not call my DLL when either a process is being debugged or killed.

Anyway - I have to fix this soon. I quite like the s_griffin idea - could you point me at the right system calls ? I could quite easily add a process list to the DLL and use that.

nietod noted that it would not work for the single caller case - I think it does because the lack of notification means that the DLL is NOT unloaded (I think - I will have to check). Or if it is - is there any mechanism for me to catch the unload ?

regards

0
 
LVL 22

Expert Comment

by:nietod
ID: 1413292
>> nietod noted that it would not work for the single caller case - I think
>> it does because the lack of notification means that the DLL is NOT
>> unloaded (I think - I will have to check). Or if it is - is there any
>> mechanism for me to catch the unload ?
It is unloaded, but the library entry point procedure is not called to notify it of this fact.
If there was another mechanism to catch the unload, then you could just use that mechanism to clean up.

That is why, with this approach A) you need to keep the DLL loaded with a second process and B) the DLL will need to share memory between processes.
0
 

Expert Comment

by:juhapekka
ID: 1413293
I Use Semaphores to detect if my program is run twise in the same computer, after process dies and if doesn't destroy semaphores, according to microsoft documentation, windows cleans them, and for me it have worked fine, in few seconds the semaphores are gone after the process has ended.
0
 
LVL 22

Expert Comment

by:nietod
ID: 1413294
That's true juhapekka, if many resources, including files handles, and memory mappings etc.

But what does that have to do with this question!
0
 
LVL 1

Expert Comment

by:Arkadiy
ID: 1413295
As a variation of nietod's suggestions, in your internal tables in the driver you can keep some sort of link to process that created a port with that port's info. Im user mode, I could just open a handle to process and keep asking if that process is runnig. If NT has some sort of process ID that is not likely to be reused - you can use that. Then, every time you open a port (or maybe every time you run out of resources or encounter a port alredy opened - check the processes that own those ports. If the port's process is dead, kill the driver's resources.
P.S. Come to think about it, even if NT has a process ID that is somewhat likely to be reused, that schema may still apply. So the resources willbe freed a bit later, so what? :)
0
 

Author Comment

by:mwright012397
ID: 1413296
I don't see what that has to do with the original problem ?

0
 
LVL 1

Expert Comment

by:Arkadiy
ID: 1413297
Well, unless I am mistaken, the goal is to clean up some resources allocated by the driver. Normally you do it  on PROCESS_DETACH. I suggest an alternative way to do it, some sort of garbage collection in the driver itself. Do I misunderstand the goal?
0
 

Expert Comment

by:juhapekka
ID: 1413298
Whoops... being tired misunderstood the idea... sorry.
0
 

Author Comment

by:mwright012397
ID: 1413299
Arkadiy-

Now we are getting somewhere. For my sake (being an idiot) could you expand upon "open a handle to the process". How do I tell if a process is still running ?


0
 
LVL 22

Accepted Solution

by:
nietod earned 150 total points
ID: 1413300
That's really what I was suggesting.
When a port is opened you will use GetCurrentProcessID() to get the ID of the process openign the port (since this is a call into the DLL the ID will be for the process making the call).  Then use OpenProcess()  to open a handle for that process and save it.  This needs to be save in some sort of data structure that will be shared among all applications that use the DLL.  Then when you want to check if the process that attacked to the port is still around, retreive the process handle and use WaitforSingleObject() on the handle (specify a short or 0 wait time).  If the process has terminated the handle will be signaled and this will be indicated in the return value from the the wait function (WAIT_OBJECT_O).  if the process is running, the handle will be non-signaled and the return value will be WAIT_TIMEOUT.  If you find the process has terminated, then you can take steps to clean up.  

Now whenever a port is closed (properly or by detecting a termination), you must close the process handle associated with that port with CloseHandle().

the key that makes this work, however, is having a second process to keep the DLL loaded so that the process and port information is retained even when the process that really uses the DLL crashes.

That is the general idea.  look up those functions and ask if you have questions.
0
 
LVL 1

Expert Comment

by:Arkadiy
ID: 1413301
Nietod explains the process handle nicely. However, I am not sure if the code he suggests wil work in the driver. And the main difference between my and him is that I propose to perform the garbage collection in the driver - that IS the piece of code that is shared between all instances of DLL, and it's always running, and it has its own memory. Unfortunately, I do not know how to store a process handle in kernel mode, or how to check if the process is still runniing. That's why I did not post my idea as an answer. I am not a device driver guy. Quick search in MSDN gave me PsGetCurrentProcess() and IoGetCurrentProcess(). However, I could not find PEPROCESS structure they refer to.

0
 
LVL 22

Expert Comment

by:nietod
ID: 1413302
Opps, I didn't understand arkadiy's suggestion.  I thought it was the same as mine.  I didn't realize we was proposing changing the driver.  I don't think you HAVE to change the driver, my suggestion should work without doing so, however, that may be a more direct solution.
0
 
LVL 22

Expert Comment

by:nietod
ID: 1413303
That is supposed to be "he was proposing".  Just to add more confusion by taking credit through a typo.
0

Featured Post

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

For a while now I'v been searching for a circular progress control, much like the one you get when first starting your Silverlight application. I found a couple that were written in WPF and there were a few written in Silverlight, but all appeared o…
A theme is a collection of property settings that allow you to define the look of pages and controls, and then apply the look consistently across pages in an application. Themes can be made up of a set of elements: skins, style sheets, images, and o…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

8 Experts available now in Live!

Get 1:1 Help Now