detect program termination (C, Windows)
Asked Answered
S

7

9

I have a program that has to perform certain tasks before it finishes. The problem is that sometimes the program crashes with an exception (like database cannot be reached, etc). Now, is there any way to detect an abnormal termination and execute some code before it dies?

Thanks.

code is appreciated.

Sufferable answered 8/9, 2009 at 14:9 Comment(1)
Use a SIGSEGV signal handler. ;-)Diphenylamine
P
9

1. Win32

The Win32 API contains a way to do this via the SetUnhandledExceptionFilter function, as follows:

LONG myFunc(LPEXCEPTION_POINTERS p)
{
     printf("Exception!!!\n");     
     return EXCEPTION_EXECUTE_HANDLER;
}

int main()
{
     SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)&myFunc);    
     // generate an exception !
     int x = 0;
     int y = 1/x;
     return 0;
}

2. POSIX/Linux

I usually do this via the signal() function and then handle the SIGSEGV signal appropriately. You can also handle the SIGTERM signal and SIGINT, but not SIGKILL (by design). You can use strace() to get a backtrace to see what caused the signal.

Palmore answered 9/9, 2009 at 15:26 Comment(6)
Also, regarding you comment about TerminateProcess()...the simple answer is that you can't do ANYTHING after TerminateProcess() is called for your process. Do not pass go, do not collect $200. Your process exits, now. Period. The end.Palmore
Thanks for the comments. The problem are not exceptions. The problem is detecting a crash or a call for termination. Exceptions i can handle alreadySufferable
That's what SetUnhandledExceptionFilter does, it handles "crashes" like stack overflows, null memory access, etc. It's not just an exception handler in the try/catch sense.Palmore
See msdn.microsoft.com/en-us/library/aa363082(VS.85).aspx, it delineates all of the "crashes" SEH can handle.Palmore
Also, I think the function name is confusing you. This function is specifically for handling "abnormal terminations" as you call them. In other words, this is the function that gets called when your code crashes. It can and will not handle TerminateProcess, though. So, as is pointed out by Piotr, it won't "fire" if your process is terminated via TerminateProcess, and this is by design. SEH is what is used by countless programs to "phone home" in the event of a crash.Palmore
Thanks Coleman, your comment TerminateProcess calls was not possible to delay without hooking was the answer I was looking for.Zelig
E
5

There are sysinternals forum threads about protecting against end-process attempts by hooking NT Internals, but what you really want is either a watchdog or peer process (reasonable approach) or some method of intercepting catastrophic events (pretty dicey).

Edit: There are reasons why they make this difficult, but it's possible to intercept or block attempts to kill your process. I know you're just trying to clean up before exiting, but as soon as someone releases a process that can't be immediately killed, someone will ask for a method to kill it immediately, and so on. Anyhow, to go down this road, see above linked thread and search some keywords you find in there for more. hook OR filter NtTerminateProcess etc. We're talking about kernel code, device drivers, anti-virus, security, malware, rootkit stuff here. Some books to help in this area are Windows NT/2000 Native API, Undocumented Windows 2000 Secrets: A Programmer's Cookbook, Rootkits: Subverting the Windows Kernel, and, of course, Windows® Internals: Fifth Edition. This stuff is not too tough to code, but pretty touchy to get just right, and you may be introducing unexpected side-effects.

Perhaps Application Recovery and Restart Functions could be of use? Supported by Vista and Server 2008 and above.

ApplicationRecoveryCallback Callback Function Application-defined callback function used to save data and application state information in the event the application encounters an unhandled exception or becomes unresponsive.

On using SetUnhandledExceptionFilter, MSDN Social discussion advises that to make this work reliably, patching that method in-memory is the only way to be sure your filter gets called. Advises to instead wrap with __try/__except. Regardless, there is some sample code and discussion of filtering calls to SetUnhandledExceptionFilter in the article "SetUnhandledExceptionFilter" and VC8.

Also, see Windows SEH Revisited at The Awesome Factor for some sample code of AddVectoredExceptionHandler.

Elsyelton answered 9/9, 2009 at 1:48 Comment(5)
thanks. I saw those before. there are 2 issues, tho. 1) I have to support XP. 2) I don't need to recover from a crash. I just need to save a few files and close the db connections before closing the application (either gracefully or before crashing).Sufferable
Gotcha. Added some info and links to sample code and discussion of SUEF and AVEH.Elsyelton
let me try this. Still, I can't catch a TerminateProcess. From what i am seeing this is not possibleSufferable
I believe it's possible, just a lot of work. At the kernel level you can do most anything, hook and patch most anything. Search "hook ntterminateprocess" etc. I'll expand on my first paragraph a bit, but keep in mind that they make it difficult because they don't want an arms race. I.e. the next question someone will ask is "how do i kill an errant process that refuses to immediately terminate?" We're in device driver, anti-virus, rootkit areas here.Elsyelton
:) Didn't think you were. Have the other methods like SUEF, AVEH, signal handlers, watchdog proc, or __try/__except worked for all the cases you need? If so, then that's the way to go (and please report what worked for you--it's an interesting topic). If you need more, you're going to have to use some atypical techniques.Elsyelton
R
2

It depends what do you do with your "exceptions". If you handle them properly and exit from program, you can register you function to be called on exit, using atexit().

It won't work in case of real abnormal termination, like segfault.

Don't know about Windows, but on POSIX-compliant OS you can install signal handler that will catch different signals and do something about it. Of course you cannot catch SIGKILL and SIGSTOP.

Signal API is part of ANSI C since C89 so probably Windows supports it. See signal() syscall for details.

Rozanneroze answered 8/9, 2009 at 14:38 Comment(1)
I'm using something similar to catch ctrl-c and other termination signals but I can't catch a TerminateProcess. If I remember correctly you can't stop a SIGKILL, the same applies to TerminateProcess. It just causes the app to die.Sufferable
M
1

If it's Windows-only, then you can use SEH (SetUnhandledExceptionFilter), or VEH (AddVectoredExceptionHandler, but it's only for XP/2003 and up)

Mize answered 8/9, 2009 at 14:31 Comment(4)
i think this might help. do you have a sample snippet?Sufferable
codepad.org/mUAUB25D - but that's the simplest one, there are more complex crash handlers on the net (e.g. on CodeProject).Mize
I tried, it looked good but I if I killed the process (from the task manager, etc) it doesn't detect it.Sufferable
From MSDN: "If a process is terminated by TerminateProcess, all threads of the process are terminated immediately with no chance to run additional code. This means that the thread does not execute code in termination handler blocks. In addition, no attached DLLs are notified that the process is detaching.".Mize
A
0

Sorry, not a windows programmer. But maybe

_onexit()

Registers a function to be called when program terminates.

http://msdn.microsoft.com/en-us/library/aa298513%28VS.60%29.aspx

Anthroposophy answered 8/9, 2009 at 14:38 Comment(1)
thanks but it doesn't really help. I can catch a normal termination.Sufferable
D
0

First, though this is fairly obvious: You can never have a completely robust solution -- someone can always just hit the power cable to terminate your process. So you need a compromise, and you need to carefully lay out the details of that compromise.

One of the more robust solutions is putting the relevant code in a wrapper program. The wrapper program invokes your "real" program, waits for its process to terminate, and then -- unless your "real" program specifically signals that it has completed normally -- runs the cleanup code. This is fairly common for things like test harnesses, where the test program is likely to crash or abort or otherwise die in unexpected ways.

That still gives you the difficulty of what happens if someone does a TerminateProcess on your wrapper function, if that's something you need to worry about. If necessary, you could get around that by setting it up as a service in Windows and using the operating system's features to restart it if it dies. (This just changes things a little; someone could still just stop the service.) At this point, you probably are at a point where you need to signal successful completion by something persistent like creating a file.

Destroyer answered 8/9, 2009 at 23:59 Comment(1)
I agree with you. My main problem is performing one last action before dying at a TerminateProcess or other unforeseen event. The rest of the events are taken care of. I talked to the person in charge of the project about converting the monitoring app to a service but that's a no. I guess there is no way of doing this...Sufferable
D
0

I published an article at ddj.com about "post mortem debugging" some years ago.

It includes sources for windows and unix/linux to detect abnormal termination. By my experience though, a windows handler installed using SetUnhandledExceptionFilter is not always called. In many cases it is called, but I receive quite a few log files from customers that do not include a report from the installed handlers, where i.e. an ACCESS VIOLATION was the cause.

http://www.ddj.com/development-tools/185300443

Deluge answered 9/9, 2009 at 15:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.