Redirect c++ crash to stderr - c++

Considering a small program like this :
int main()
{
freopen("./stdout.log", "w", stdout);
freopen("./stderr.log", "w", stderr);
int a = 1 / 0;
}
and considering my program is ran by a third party software where I can't change neither how the program is launched nor the environment.
How to properly catch the Floating point exception (core dumped) message issued by the division by zero and any other messages that would still be printed on the tty ?
I've tried to search SO for similar answer but I might be just typing the wrong keywords as it seems a common practice.

Matthieu Brucher's comment is correct:
You need to catch the signals, which is platform dependent.
From the text of the message, I infer that you may be running on a Linux platform. If so, you can catch the SIGFPE signal.
#include <stdexcept>
#include <signal.h>
// compile with -fnon-call-exceptions (for gcc)
signal(SIGFPE, [](int signum) { throw std::logic_error("FPE"); });
The linked answer has some C++ niceties such as using a std::shared_ptr for RAII management of the signal handler and mentions compiler flags needed for gcc to make that work.
The Linux Programming Interface book also has a pure-C example.
In Windows, you can use Structured Exception Handling (SEH) and the concept is similar (although the functions you need to call are not).
Note that in either case you're relying on platform-specific behavior not specified by C++ (division by zero is undefined behavior) so obviously this will not result in portable code.

Related

Catching fortran runtime errors and signals in C++ binding

I would like to be able to catch a terminating Fortran runtime errors in a C++ binding.
I have a legacy F90 code to bind to and expect all kind of errors e.g. numerical, IO etc.
I managed to handle STOP according to:
Intercepting Fortran STOP from C++
and able to throw/catch exception for this case in the C++ code.
I got some understanding 'Signal Handling in Fortran' at
https://www.sharcnet.ca/help/images/4/42/Fortran_Signal_Handling.pdf
However I do not manage with this, an example for f90 fortran would be very helpful.
For example trying to open a non existant file in the fortran subroutine would give a runtime error, and the C++ code terminates:
open (unit=13,FILE="fnameBAD",status="old",action="read",position="rewind")
Fortran runtime error: Cannot open file 'fnameBAD': No such file or directory
I would like to be able to catch this and other runtime errors using signals.
This won't work, at least for GFortran. When then OPEN statement fails, the GFortran runtime library will shut itself down, and only finally is the signal generated. So by the time you can catch the signal in the signal handler, libgfortran has already shut itself down (including closing all open files).
The solution, as Vladimir F says in a comment, is to catch the error in the OPEN statement with the iostat= specifier.
I've implemented something like that for unittesting C-bindings for a Fortran code from C/C++ to catch abort calls using setjmp and longjmp (essentially the same as an answer in the already linked question):
#include <setjmp.h>
#include <signal.h>
jmp_buf jmp_env;
void on_sigabrt(int signum)
{
(void) signum; // silence "unused parameter" warning
longjmp(jmp_env, 1);
}
void func()
{
if (setjmp(jmp_env) == 0) {
signal(SIGABRT, &on_sigabrt);
/* YOUR CALLS HERE */
} else {
/* ERROR HANDLING GOES HERE */
}
}
The problem #janneb already described remains: Even while longjmp should restore the stack to the point of the setjmp, it does not guarantee that all internal state in the Fortran runtime library is restored.
In fact, both books Modern Fortran: Style and Usage (rule 182) and The Fortran 2003 Handbook (15.6.4) mention that Fortran code should not be wrapped in between setjmp and longjmp.
On the other hand, there are compiler vendors which explicitly provide setjmp/longjmp wrappers (Oracle for example), as well as several projects with a similar focus:
funwind
zsvjmp
That being said, it is likely a better (and more portable) approach to use proper error handling using the iostat attribute whenever possible, as others already commented.

How to catch C++ exceptions in C? [duplicate]

I am developing C++ component dll that can be used by C or C++ applications.
The exposed dll functions are as follows
#include <tchar.h>
#ifdef IMPORT
#define DLL __declspec(dllimport)
#else
#define DLL __declspec(dllexport)
#endif
extern "C" {
DLL bool __cdecl Init();
DLL bool __cdecl Foo(const TCHAR*);
DLL bool __cdecl Release();
}
the internal implementation of these functions are C++ classes which are not exposed, I assume using this style the dll can be used either in C or C++ apps.
The problem is I do not handle any type of c++ exception (i.e. bad_alloc) and I left this stuff to the caller (the higher layer).
After much debate with my colleagues that I should catch all the exceptions and return error code or at least false because in case of C application it can not handle C++ exceptions? is that true? and what I should do in general? is there a rule of thumb for handling exeptions if you are developing component that will be used by other system.
C doesn't have exceptions, therefore in general you should catch all exception and return an error code and/or provide a function that returns the information about the last error.
If this is Windows using MSVC then yes you can catch exceptions in C but you can't catch them that well. C++ exceptions are fed through the OS ABI's Structured Exception Handling mechanism, and Microsoft have a __try, __except, __finally C extension to handle OS structured exceptions. Note that these include access violations, divide-by-zero, etc. that you'd normally want to terminate your program and log a bug report. You can identify C++ exceptions by code 0xE04D5343 (4D 53 43 = "MSC") and throw the rest on.
That all said, you probably don't want to be throwing exceptions across a DLL boundary, and certainly not if you're only exposing a C API.
As a general rule, you should never allow C++ exceptions to propagate beyond a module's boundary. This is because the C++ standard does not specify how exception propagation has to be implemented, and as such this is compiler (and compiler flags) and operating system dependent. You cannot guarantee that the code calling your module will be compiled with the same compiler with the same compiler flags as your module. In fact, as you're demonstrating with this question is that you cannot guarantee that code calling your module will be written in the same language.
For more details, please refer to Item 62 in C++ Coding Standards by Sutter and Alexandrescu.
Ok, since it was asked for:
C++ example code:
#include <typeinfo>
#include <exception>
extern "C" {
void sethandler(void (*func)(void)) { std::set_terminate(func); }
int throwingFunc(int arg) {
if (arg == 0)
throw std::bad_cast();
return (arg - 1);
}
}
C example code:
#include <stdio.h>
extern int throwingFunc(int arg);
extern void sethandler(void (*func)(void));
void myhandler(void)
{
printf("handler called - must've been some exception ?!\n");
}
int main(int argc, char **argv)
{
sethandler(myhandler);
printf("throwingFunc(1) == %d\n", throwingFunc(1));
printf("throwingFunc(-1) == %d\n", throwingFunc(-1));
printf("throwingFunc(0) == %d\n", throwingFunc(0));
return 0;
}
When I compile these two, link them together and run this (Ubuntu 10.04, gcc 4.4.5, x64), I get:
$ ./xx
throwingFunc(1) == 0
throwingFunc(-1) == -2
handler called - must've been some exception ?!
Aborted
So while you can catch exceptions from C, that's hardly sufficient - because C++ runtime behaviour after std::terminate() is undefined, and because the handler gets no status information whatsoever (to distiguish exception types and/or sources). The handler cannot clean up anything.
Btw, I've deliberately chosen std::bad_cast() as exception type in this example. This is because throwing that illustrates a difference in behaviour between std::set_unexpected() and std::set_terminate() - the unexpected handler will get called for all non std::bad_* exceptions, while in order to catch standard exceptions, a terminate handler is required ... see the dilemma ? The harness is too wide to be of practical use :(
Only propagate exceptions to the caller if the caller is designed to handle them. I guess in your case terminate() will be called immediately once any exception escapes C++ code because from the point of C++ runtime that exception has not been handled.
The same situation arises in COM servers design - the clients can be in whatever language/technology. The rul is that no exceptions should escape COM server methods - all exceptions must be caught and translated in HRESULT and (optionally) IErrorInfo. You should do similarly in your situations.
In case C code is sandwiched between two layers of C++ code propagating exceptions to C code is still a very bad idea.

How to report a stack buffer overrun on Windows?

In the code shown below I have used all documented ways to detect an exception and produce a diagnostic. It uses the C++ try/catch keywords, catches an SEH exception with the __try/__catch extension keywords, uses the Windows' AddVectoredExceptionHandler() and SetUnhandledExceptionFilter() winapi functions to install VEH/SEH filters.
Running this with Visual C++ 2003:
/GS: outputs "hello,world!" and terminates with exit code 0.
/GS-: outputs "hello,world!" and terminates with exit code 0.
Running this with Visual C++ 2013:
/GS: no output, terminates with exit code -1073740791
/GS-: outputs "hello,world!" and terminates with exit with 0.
How do I produce a diagnostic in a VS2013 compiled program with /GS in effect?
#include "stdafx.h"
#include <Windows.h>
#define CALL_FIRST 1
#define CALL_LAST 0
LONG WINAPI MyVectoredHandler(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
UNREFERENCED_PARAMETER(ExceptionInfo);
printf("MyVectoredHandler\n");
return EXCEPTION_CONTINUE_SEARCH;
}
LONG WINAPI MyUnhandledExceptionFilter(_In_ struct _EXCEPTION_POINTERS *ExceptionInfo)
{
printf("SetUnhandledExceptionFilter\n");
return EXCEPTION_CONTINUE_SEARCH;
}
void f()
{
__try
{
char p[20] = "hello,world!";
p[24] = '!';
printf("%s\n", p);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
printf("f() exception\n");
}
}
int _tmain(int argc, _TCHAR* argv[])
{
AddVectoredExceptionHandler(CALL_FIRST, MyVectoredHandler);
SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
try{
f();
}
catch (...){
printf("catched f exception\n");
}
return 0;
}
The CRT function that handles stack buffer overruns detection, __report_gsfailure(), assumes that the stack frame corruption was induced by a malware attack. Such malware traditionally messed with the fs:[0] SEH exception filters (stored on the stack frame) to get an exception handler to trigger the malware payload. One of the ways to get data to turn into executable code.
So that CRT function cannot assume that throwing an exception is safe to do. And no longer does in the CRT included with VS2013, goes back to ~VS2005. It will failfast if the OS supports it and, if not, ensures that a registered VEH/SEH exception handler cannot see the exception either. Kaboom, crash to the desktop with no diagnostic unless you have a debugger attached.
The /SAFESEH option defeats this kind of malware attack so it isn't as serious as it once was. If you are still at the stage where your code suffers from stack corruption bugs and your app is not popular enough to become the target of malware then replacing the CRT function is something you could consider.
Do talk this over with your supervisor, you never want to be personally responsible for this given the enormous liability to your client. History rarely tells the tale of what happened to the one programmer whose code put an entire corporation out of business for a month. But surely wasn't anything pretty.
Paste this code somewhere close to your main() function:
__declspec(noreturn) extern "C"
void __cdecl __report_gsfailure() {
RaiseException(STATUS_STACK_BUFFER_OVERRUN, EXCEPTION_NONCONTINUABLE, 0, nullptr);
}
And plan to remove it again soon.
There is no solution for the question as asked.
Overrunning an array causes undefined behaviour in standard C++, so no particular result is guaranteed. Failure to give a reliable result is not a problem with the compiler - it is permitted behaviour.
I'm aware of no implementation that guarantees any specific behaviour in response to an overrun - VS certainly doesn't. Which is hardly surprising as compilers are not required to do that (that is, essentially, the meaning of undefined behaviour). The reason that is the case is that it is often difficult to reliably or consistently detect such occurrences.
This means the only consistent way to detect an array overrun is to check that array indices are valid BEFORE using them to access an array element and take appropriate actions (e.g. throw an exception which can be caught instead of doing the bad operation). The downside is that it does not provide a simple or reliable way to catch errors in arbitrary code - short of modifying all code to do the required checks.
I would have liked to comment on the accepted answer, but I just joined and don't have enough reputation to do that yet.
I tried the solution with Visual Studio 2017 and had to make a couple of changes to get the solution to compile.
First I had to change the signature of __report_gsfailure to match one of Microsoft's header files to fix a compilation error.
__declspec(noreturn) extern "C" void __cdecl __report_gsfailure(_In_ uintptr_t _StackCookie)
{
RaiseException(STATUS_STACK_BUFFER_OVERRUN, EXCEPTION_NONCONTINUABLE, 0, nullptr);
}
Next I encountered a LNK2005 error, which I was able to correct by adding /FORCE:MULTIPLE to the Linker->Command Line for my project's properties.

Trapping floating point exceptions in mixed C/Fortran code

I apologize for asking a question that has been asked numerous times before. But after several searches, I realize that I may have a fundamental misunderstanding between how FPEs are to be treated in C/C++ vs. how they are treated in Fortran.
In Fortran (GNU fortran to be precise), if one wants to trap a floating point exception (use of a NAN for example), the compiler flag -ffpe-trap=invalid does the trick. The floating point exception is raised as soon as the offending statement has been executed.
In C (GNU gcc), however, this does not seem to be the case. Even more annoying (but perhaps not surprising) is that same fortran code, when called from a C main does not raise an exception (and halt execution), whereas it does when called from a Fortran main program. And this seems to be independent of whether a C or gfortran linker is used.
After much searching and reading, I see that there is C/C++ functionality available in fenv.h that suggests the "C way" of handling exceptions. I see that I can set exception flags and later check to see if exceptions have been raised. I can see how this approach might give one more flexibility over how exceptions are handled. Is this the "best practice" way of handling exceptions in C? For scientific programming (where C is often used to call fortran code) it seems inconvenient to have to have some advanced knowledge of where the exceptions might be occurring.
Is there no (straightforward) way in C to have the code that halts at the first appearance of an exception? Or is there another paradigm when it comes to exception handling in C that I am not fully grasping?
Since you use GNU utilities I will assume that you are on *nix. You need to enable floating point exceptions. When that is done, exceptions are delivered using signals. The following code illustrates it:
#include <fenv.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
void handler(int sig) {
printf("Floating Point Exception\n");
exit(0);
}
int main(int argc, char ** argv) {
feenableexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW);
signal(SIGFPE, handler);
float a = 42.0, b = 0.0, res;
res = a / b;
return 0;
}
Link with libm:
gcc -o test test.c -lm
On Windows I believe you need to use a structured exception handler: http://msdn.microsoft.com/en-us/library/windows/desktop/ms680657(v=vs.85).aspx
In the following code, I show how do do exactly what I was aiming to do with my question above. It relies on the Mac OSX extension mentioned here and the signalling value described
here.
I am not an expert in either of these topics, so can make no claims as to how portable this code is. But it does do the two things I wanted : It allows me to initialise data to a "NAN", and later trap invalid use of these uninitialized values. The trap is detected by both normal execution and in gdb.
I would certainly appreciate any comments on this solution.
#include "fp_exception_glibc_extension.h"
#include <fenv.h>
#include <signal.h>
#include <stdio.h>
/*
-----------------------------------------------------------------------
This example illustrates how to initialize data with an sNAN. Later, if
the data is used in its 'uninitialized' state, an exception is raised,
and execution halts.
The floating point exception handler 'fp_exception_glibc_extension' is
needed for OS X portability.
At least two blog posts were used in writing this :
"Update: Floating-point exception handling on Mac OS X"
http://philbull.wordpress.com/2012/12/09/update-floating-point-exception-handling-on-mac-os-x/
Note : there is a lengthy email exchange about how portable this extension is; see
comments in the text of the code.
"NaNs, Uninitialized Variables, and C++"
http://codingcastles.blogspot.fr/2008/12/nans-in-c.html
-----------------------------------------------------------------------
*/
void set_snan(double& f)
{
*((long long*)&f) = 0x7ff0000000000001LL;
}
int main()
{
/* On OS X, this extension is provided by
'fp_exception_glibc_extension.{c,h} */
feenableexcept(FE_INVALID);
double p;
set_snan(p); /* Initialize to signaling nan */
double q;
q = 2*p; /* Floating point exception is trapped here */
printf("p = %f; q = %f\n",p,q);
}

Why does GCC report a Floating Point Exception when I execute 1/0?

Stroustrup says, in "The Design and Evolution of C++" (Addison Wesley, 1994), "low-level events, such as arithmetic overflows and divide by zero, are assumed to be handled by a dedicated lower-level mechanism rather than by exceptions. This enables C++ to match the behaviour of other languages when it comes to arithmetic. It also avoids the problems that occur on heavily pipelined architectures where events such as divide by zero are asynchronous."
Q1: If it's not an exception, why does GCC report one as opposed to a lower-level error?
Q2: Given I'm dividing integers, why is it reported as floating point ?
Given I cannot catch it with catch(...), it is very misleading. Obviously I can test and avoid the whole 'error', but my point is that it is very confusing for a beginner who thinks that it might be an exception (reasonable), tries to catch it , then finds out that it's NOT AN EXCEPTION , and wonders about the run-time exception reported.
My compiler is gcc version 4.2.1 (Apple Inc. build 5666) (dot 3)
Some accurate clarification of the difference between CPU exceptions, FPU exceptions, Language exceptions and OS exceptions might resolve this.
Example Program:
int main(){
int i=1/0;
return i;
}
Resulting Output:
Floating point exception
A floating-point exception (FPE) is not a C++ exception. There are several types of exceptions in various systems, and they are not interchangeable. An FPE is an exception at the microprocessor or ISA level, but not at the C++ level. An FPE may result in the firing of a signal called SIGFPE, which you can handle but not using C++ try/catch. If you want to handle it you can use the POSIX function sigaction (I think on Windows one would use Structured Exception Handling).
Exceptions, in the C++ sense, are software-detected errors. When you divide by zero, its typically the hardware that detects the issue and it asserts a hardware exception (same name, similar concept, different beast). The operating system's hardware exception handler receives this and decides what to do. A typical OS reaction is to send a signal to the process that was running at the time of the hardware exception (if the system was running in user mode), and let that process's signal handler decide how to handle things.
Ancient history folded both floating point error and division by zero into SIGFPE. While you can on receiving the exception decode it to determine which, the shell doesn't.
The following little program catches a floating point error and prints out information about the signal. Note that from a C language standpoint a division by zero is undefined behavior. For example, not all systems have POSIX signals. Because the compiler can trivially predict the error, it may even on POSIX systems decide to simply eliminate all code, or exit immediately with an error. (I would hope and assume that a compiler on POSIX systems will produce a program which does the expected thing. Below it does. But such hopes have been disappointed before.)
#include <stdio.h>
#include <signal.h>
#include <stdlib.h> // for exit()
void fpehandler (int sig, siginfo_t *info, void *uc)
{
fprintf (stderr,
"Caught signal no. %d; code: %d (FPE_INTDIV would be %d)\n",
sig, info->si_code, FPE_INTDIV);
if(info->si_code == FPE_INTDIV)
{
fprintf (stderr,
"Yes, the error was an integer division by zero.\n");
}
// It's not officially safe to return from a handler
// of a "program error signal" (of which SIGFPE is an example).
// Plus many functions are not strictly safe to
// call in a signal handler (e.g. exit()).
// See https://www.securecoding.cert.org/confluence/display/c/SIG30-C.+Call+only+asynchronous-safe+functions+within+signal+handlers .
// We call _Exit().
_Exit(0); // success, isn't it?
}
int main(void)
{
struct sigaction sa;
sigemptyset (&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = fpehandler;
sigaction (SIGFPE, &sa, NULL);
// cause "floating point" error
printf("%d\n", 2/0);
// ---- below is unreachable code ;-) ----------
// We shouldn't be here. Something went wrong. return 1.
return 1;
}
When I run it under cygwin, gcc 5.4.0, it prints
$ gcc -Wall float-except.c -o float-except && ./float-except
float-except.c: In function 'main':
float-except.c:28:21: warning: division by zero [-Wdiv-by-zero]
printf("%d\n", 2/0);
^
Caught signal no. 8; code: 15 (FPE_INTDIV would be 15)
Yes, the error was an integer division by zero.