MessageBox “Abnormal program termination” keeps my

2019-04-28 00:41发布

问题:

...kind of. As illustrated by this extremely simplistic example,

very rarely (only once reported so far), it happens that one of my applications crashes this way. I want to terminate it as I normally do when an unspecific exception occurs. My strategy is to (low-level) log the problem, then terminate. The application is part of a subsystem and I want to (re)start it, if any problem is detected. It's built with C++-Builder 6 and runs on Windows (XP...7, also 8). I learned that an abort() most probably caused the error message. The application has a GUI, that's why a message box is shown instead of just making an (unblocking) output to stderr.

And as long as the message box isn't accepted by a user, my application keeps obviously running, for example it handles timers (the lifebeats in the above example increase) or inter-process messages, fully unaware about the problem.

After reading some answers to What is the easiest way to make a C++ program crash? and Difference between raise(SIGABRT) and abort() methods, I tried the following

void mySignalHandler(int sig)
{
    // low-level error reporting here
    exit(-1);
}

void __fastcall TForm1::FormCreate(TObject *Sender)
{
    signal(SIGABRT, mySignalHandler);
    // some more initialisation here
}

which lets my application terminate properly also if abort() or raise(SIGABRT) is called. (I also wish to prevent Windows from "searching for a solution of the problem".)

Is this (registering a signal handler for abort and calling exit there) reliable from your point of view? ...or at least something one can build upon?

回答1:

In the C++Builder installation folder, check the following files:

  • source\cpprtl\Source\misc\errormsg.c - implementation of _ErrorMessage
  • source\cpprtl\Source\procses\abort.c - implementation of abort, which calls _ErrorMessage
  • source\cpprtl\Source\misc\assert.c - implementation of _assert, which calls _ErrorMessage

errormsg.c defines an undocumented _messagefunc function pointer that you can set to override the default behavior. Although it's undocumented and not declared in any header files, you can declare it as an extern and access it that way. Sample usage:

extern int (_RTLENTRY * _EXPDATA _messagefunc)(char *msg);

static int LogAndDie(char *msg)
{
  LogMessageToSomeFile(msg);
  exit(1);
  return 0;
}

void InitializeErrorHandling()
{
  _messagefunc = LogAndDie;
}


回答2:

You might be able to use Windows Error Reporting to create a dump of the process, when an unhandled exception causes a termination. Then you can review the dump at your leisure and allow some parent-process or other watchdog to restart your process. If you chose this strategy, you would not try to deal with the failure in your code, but to allow it.



回答3:

If you want to capture any program exit you should look at atexit(). If you want to capture all termination events then look at std::set_terminate(), if you want to caputure all unexpected exceptions then look at std::set_unexpected(). If you want to capture only abort() you can call signal() with the SIGABRT signal value. You can also wrap your code with try{your code}catch(...){custom event handler}.



回答4:

I could do some tests, and I only can confirm that registering a SIGABRT signal handler is simply a NOOP.

I tried it with a very simple GUI application written with VS2008 Express. :

  • no framework, nor .NET but only Win API
  • one menu with Exit and Fatal
  • menu managed directly in WndProc
  • Fatal execute 1/0

Here are the result :

  • no special action => windows opens a MessageBox indicating a fatal error ...
  • signal handler for SIGABRT => same MessageBox
  • C++ try catch(...) => same MessageBox
  • SEH in WndProc : can intercept the error !
  • SEH around message loop : can intercept the error !

If I put bot SEH handlers, the most internal (WndProc) catches.

The good new for you is that if is enough to protect the message loop, and you do not have to go into every WndProc.

The bad new is that I do not know C++ builder and cannot say where to find the message loop.

Just to give you a clue, here is how I could protect the message loop in a WinAPI application :

__try {
while (GetMessage(&msg, NULL, 0, 0))
{
    if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}
}
__except (EXCEPTION_EXECUTE_HANDLER){
    ::MessageBox(NULL, _T("FATAL"), _T("MAIN"), MB_OK | MB_ICONERROR);
}

That way, I can see my own message box, but nothing else and if I comment my message box the application silently exits.

But ... as the message you show is not original Windows one, I suspect C++ builder to already have such an exception handler in its message loop.

Hope it helps ...