views:

1375

answers:

8

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.

A: 

C doesn't really support "exceptions" as you'd see them in C++ or Java. What you should be doing is checking return codes and acting accordingly. How does your current program indicate that your database cannot be reached? I would expect that somewhere in there, it returns an error code - maybe a negative number, or maybe just something that isn't zero. It depends on the convention in use.

When you're writing C, it's really important to check return values so that you can handle exceptional cases without crashing.

As for an example, I would do something like this:

int status = 0;
status = access_database();
if (status != 0)
{
    execute_some_code_before_death();
    exit(1);
}

If the function you're calling sets errno, you can use perror to get more information about the error.

Matt Ball
Thanks for the comments. My problem is not on a normal run. I can check return codes. The problem is when the program is being signal to terminate by either terminateProcess() or an exception occurred that caused the program to crash.
wonderer
+1  A: 

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

PiotrLegnica
i think this might help. do you have a sample snippet?
wonderer
http://codepad.org/mUAUB25D - but that's the simplest one, there are more complex crash handlers on the net (e.g. on CodeProject).
PiotrLegnica
I tried, it looked good but I if I killed the process (from the task manager, etc) it doesn't detect it.
wonderer
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.".
PiotrLegnica
+2  A: 

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.

qrdl
yes... I need to be able to detect a normal and abnormal termination...
wonderer
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.
wonderer
A: 

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

DanM
That's C++, not C.
Matt Ball
thanks but it doesn't really help. I can catch a normal termination.
wonderer
+2  A: 

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.

Brooks Moses
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...
wonderer
+2  A: 

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.

bill weaver
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).
wonderer
Gotcha. Added some info and links to sample code and discussion of SUEF and AVEH.
bill weaver
let me try this. Still, I can't catch a TerminateProcess. From what i am seeing this is not possible
wonderer
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.
bill weaver
yes... but I am not coding a rootkit or driver here...
wonderer
:) 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.
bill weaver
+2  A: 

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.

Coleman
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.
Coleman
Thanks for the comments. The problem are not exceptions. The problem is detecting a crash or a call for termination.Exceptions i can handle already
wonderer
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.
Coleman
See http://msdn.microsoft.com/en-us/library/aa363082(VS.85).aspx, it delineates all of the "crashes" SEH can handle.
Coleman
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.
Coleman
not what I needed, but close enough
wonderer
Thanks Coleman, your comment TerminateProcess calls was not possible to delay without hooking was the answer I was looking for.
Stefan Lundström
A: 

I published a articel 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. a ACCESS VIOLATION was the cause.

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

RED SOFT ADAIR
thanks. my problem tho are hot exceptions.
wonderer