C++: Terminate called without an active exception (GCC) - c++

Consider the following program:
#include <iostream>
#include <pthread.h>
#include <stdexcept>
#include <unistd.h>
static void* busy(void*)
{
int oldstate ;
auto result = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,&oldstate) ;
if (result != 0)
#ifdef NOEXCEPT
{ std::cerr << "pthread_setcanceltype" << std::endl ; abort() ; }
#else
throw std::runtime_error("pthread_setcanceltype") ;
#endif
while (true)
;
return nullptr ;
}
static pthread_t start()
{
pthread_t t ;
int result = pthread_create(&t,nullptr,busy,nullptr) ;
if (result != 0)
throw std::runtime_error("pthread_create") ;
return t ;
}
static void terminate(pthread_t t)
{
auto result = pthread_cancel(t) ;
if (result != 0)
throw std::runtime_error("pthread_cancel()") ;
result = pthread_join(t,nullptr) ;
if (result != 0)
throw std::runtime_error("pthread_join()") ;
}
int main()
{
auto t = start() ;
sleep(1) ; // may not cause an abort otherwise
terminate(t) ;
return 0 ;
}
This runs fine as long as no optimization (or -O1) is used, e.g. with g++ -std=c++11 -Wall -o test test.cc -pthread
However, with -O2 or -O3 the program aborts with the message above.
Also kind of interesting: it runs thru if compiled with -DNOEXCEPT. So it appears, if a thread is cancelled in a function that potentially [sic!] throws an exception, and if optimization is switched on, the program may abort. -- And I can't see any way to prevent this.
It's for me reproducible on amd64 gcc 4.8.4 (Ubuntu 14.04.3) and armv7l gcc 4.9.2 (Raspbian 4.9.2-10).
Can you reproduce this? Do you have an explanation? This behavior seems to be odd (at least to me). I'd be happy to receive some kind of feedback. Thank you!

On Linux (as on most OSes) exceptions are a language-agnostic feature, and pthread cancellation is implemented using language-agnostic exceptions (See e.g. Cancellation and C++ Exceptions).
When a pthread cancellation is delivered to a thread (using a signal, but you don't need to know that) the unwind machinery invokes all the installed personalities so that they can perform language-specific cleanup prior to the thread exiting. (This is pretty cool; it means that as in the above article you can insert a catch block for abi::__forced_unwind to detect - though not to prevent - a thread cancellation.)
The problem is that an asynchronous cancellation can occur at any instruction, and the C++ exception tables generated by g++ only handle exceptions occurring at instructions known to be capable of generating exceptions (i.e. but not only calls to exception-throwing functions). If an exception is generated at a point not covered by the C++ tables, the C++ personality panics and terminates the process (hence "terminate called without an active exception").
The reason this is influenced by optimization is that the C++ personality is installed lazily, but with higher optimization levels the compiler might decide to preemptively install the C++ personality. You can guarantee the crash even at lower optimization levels by exercising the C++ exception machinery e.g. with try { throw 0; } catch (int) {}.
The simplest fix is to ensure that the C++ personality is not installed in the thread you want to asynchronous cancel. You can ensure this by compiling the thread function as C and not calling any C++ functions from it.
A more hacky and highly unsupported solution is to ensure that all the asynchronous cancellation points (that is, all the instructions where the cancelled thread could be when the asynchronous cancellation is received) are in fact covered by the C++ unwind tables. Firstly you need to compile with -fnon-call-exceptions; secondly you have to ensure that every instruction that could be an asynchronous cancellation point is between two points known to be synchronous cancellation points, e.g. pthread_testcancel:
static void* busy(void*)
{
int oldstate ;
auto result = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,&oldstate) ;
if (result != 0)
#ifdef NOEXCEPT
{ std::cerr << "pthread_setcanceltype" << std::endl ; abort() ; }
#else
throw std::runtime_error("pthread_setcanceltype") ;
#endif
pthread_testcancel();
for (unsigned i = 1; ; ++i)
if (i == 0)
pthread_testcancel();
return nullptr ;
}

Somebody wrote here that a program aborts "when a thread object goes out of scope and it is in joinable state".
That is what 39.3.1.3/1 [thread destructor] says actually:
If joinable(), calls std::terminate(). [...] Thus the programmer must ensure that the destructor is never executed while the thread is still joinable.

Related

Different behavior of boost::future and std::future

To be specific, boost::future doesn't seem to block in the destructor. And boost documentation didn't mention it. However std::future did mention it.
If I want to chain some .then() to boost::future I also need to chain a .get() call at the end to force the temporary object to block to get the correct behavior. Is that the right way of using it?
void a()
{
boost::async([] {
boost::this_thread::sleep_for(boost::chrono::seconds{1});
std::cout << "Finished sleeping\n";
return 1;
});
std::cout << "End of a()\n";
}
void b()
{
std::async([] {
std::this_thread::sleep_for(std::chrono::seconds{1});
std::cout << "Finished sleeping\n";
return 1;
});
std::cout << "End of b()\n";
}
int main()
{
a();//No finished sleeping printed
std::cout << "End of main()\n";
}
int main()
{
b();//finished sleeping will print
std::cout << "End of main()\n";
}
https://www.boost.org/doc/libs/1_75_0/doc/html/thread/synchronization.html
The returned futures behave as the ones returned from boost::async, the destructor of the future object returned from then will block. This could be subject to change in future versions.
(2015) https://www.boost.org/doc/libs/1_75_0/doc/html/thread/changes.html
Version 4.5.0 - boost 1.58
Fixed Bugs:
#10968 The futures returned by async() and future::then() are not blocking.
(2017) https://github.com/boostorg/thread/issues/194
I'm aware of the issue. Boost.thread did it by design following std::async and the first proposals of std::future::then.
The problem is that changing the behavior (even if it is not desired in some contexts) would be a breaking change. I would need to crate a new version, but Idon't want to create a new version using compiler flags as this has become a nightmare to maintain.
So I will need to create a boost/thread_v5 which will produce different binaries lib_boost_thread_v5.a. Boost.Threads is not structured this way, and this will mean a lot of work.
This is the single way to avoid breaking changes, but before doing that I would like to enumerate all the breaking changes that should be on this new version.
It seems the destructor of future object returned from async has really changed to non-blocking at some time point after 2017, so you should use .get() to block.
I can not make it block because:
BOOST_THREAD_FUTURE_BLOCKING(not documented) is not #defined in all cases;
if you #define BOOST_THREAD_FUTURE_BLOCKING manually, you can see that ~future_async_shared_state_base() will be called when the future is destroyed and the lambda passed to async has finished running (i.e. when the boost::shared_ptr's use_count drops from 2 to 1 to 0), so the destructor of future object returned from async (when the boost::shared_ptr's use_count drops from 2 to 1) will still not block.
https://www.boost.org/doc/libs/1_75_0/boost/thread/detail/config.hpp
#if BOOST_THREAD_VERSION>=5
//#define BOOST_THREAD_FUTURE_BLOCKING
#if ! defined BOOST_THREAD_PROVIDES_EXECUTORS \
&& ! defined BOOST_THREAD_DONT_PROVIDE_EXECUTORS
#define BOOST_THREAD_PROVIDES_EXECUTORS
#endif
#else
//#define BOOST_THREAD_FUTURE_BLOCKING
#define BOOST_THREAD_ASYNC_FUTURE_WAITS
#endif
https://www.boost.org/doc/libs/1_75_0/boost/thread/future.hpp
in async:
void init(BOOST_THREAD_FWD_REF(Fp) f)
{
#ifdef BOOST_THREAD_FUTURE_BLOCKING
this->thr_ = boost::thread(&future_async_shared_state::run, static_shared_from_this(this), boost::forward<Fp>(f));
#else
boost::thread(&future_async_shared_state::run, static_shared_from_this(this), boost::forward<Fp>(f)).detach();
#endif
}
when the future is destroyed and the lambda passed to async has finished running:
~future_async_shared_state_base()
{
#ifdef BOOST_THREAD_FUTURE_BLOCKING
join();
#elif defined BOOST_THREAD_ASYNC_FUTURE_WAITS
unique_lock<boost::mutex> lk(this->mutex);
this->waiters.wait(lk, boost::bind(&shared_state_base::is_done, boost::ref(*this)));
#endif
}
C++20 has moved to coroutine which is able to split control flow in more complex cases than future.then: CppCon 2015: Gor Nishanov “C++ Coroutines - a negative overhead abstraction". You can try libraries like cppcoro or boost.fiber and pause the task function inside complex control structures (e.g. co_await inside if inside while inside for).
C++23 Executor TS: in initial versions of A Unified Executors Proposal for C++ there were OneWayExecutor execute(fire-and-forget) TwoWayExecutor twoway_execute(return a future) then_execute(take a future and a function, return a future) etc but in recent versions they were replaced by sender and receiver.

What is the difference between MinGW SEH and MinGW SJLJ?

I am just starting to learn C and installing now QT x64 (form here: http://tver-soft.org/qt64). I have two options to install: MinGW 4.9.2 SEH or MinGW 4.9.2 SJLJ.
Question: Which is better to install and why?
I read What is difference between sjlj vs dwarf vs seh? and https://wiki.qt.io/MinGW-64-bit#Exception_handling:_SJLJ.2C_DWARF.2C_and_SEH but understand nothing (new to C and compiller languages).
SJLJ and SEH are two different exception handling systems.
For the specific differences, the resources you've already seen cover everything.
However, as for which one is better to install, go with SJLJ unless you know that you need SEH.
2019 Update: On modern systems, there's no reason to use SJLJ, so the advice above should probably be flipped. SEH is more common now. Ultimately though, it doesn't really matter, since it's easy to switch between the two.
SJLJ
SJLJ is more widely supported across architectures, and is more robust. Also, SJLJ exceptions can be thrown through libraries that use other exception handling systems, including C libraries. However, it has a performance penalty.
SEH
SEH is much more efficient (no performance penalty), but unfortunately is not well-supported. SEH exceptions will cause bad things to happen when thrown through libraries that do not also use SEH.
As far as your code is concerned, there are no real differences. You can always switch compilers later if you need to.
I discovered one difference between SJLJ and SEH exception handling in MinGW-w64: C signal handlers set by signal() function do not work in SJLJ version as soon as at least one try{} block gets executed at the run time. Since this issue does not seem to be described anywhere, I am putting it here for the record.
The following example (test_signals.cpp) demonstrates this.
// This sample demonstrates how try {} block disables handler set by signal()
// on MinGW-w64 with GCC SJLJ build
#include <signal.h>
#include <iostream>
int izero = 0;
static void SIGWntHandler (int signum)//sub_code)
{
std::cout << "In signal handler, signum = " << signum << std::endl;
std::cout << "Now exiting..." << std::endl;
std::exit(1);
}
int main (void)
{
std::cout << "Entered main(), arming signal handler..." << std::endl;
if (signal (SIGSEGV, (void(*)(int))SIGWntHandler) == SIG_ERR)
std::cout << "signal(OSD::SetSignal) error\n";
if (signal (SIGFPE, (void(*)(int))SIGWntHandler) == SIG_ERR)
std::cout << "signal(OSD::SetSignal) error\n";
if (signal (SIGILL, (void(*)(int))SIGWntHandler) == SIG_ERR)
std::cout << "signal(OSD::SetSignal) error\n";
// this try block disables signal handler...
try { std::cout << "In try block" << std::endl; } catch(char*) {}
std::cout << "Doing bad things to cause signal..." << std::endl;
izero = 1 / izero; // cause integer division by zero
char* ptrnull = 0;
ptrnull[0] = '\0'; // cause access violation
std::cout << "We are too lucky..." << std::endl;
return 0;
}
Builds with:
g++ test_signals.cpp -o test_signals.exe
The expected output is:
Entered main(), arming signal handler...
In try block
Doing bad things to cause signal...
In signal handler, signum = 8
Now exiting...
The actual output when I build with MigGW-w64 SJLJ variant is:
Entered main(), arming signal handler...
In try block
Doing bad things to cause signal...
The application gets terminated silently after some delay. That is, signal handler does not get called. If try{} block is commented out, signal handler gets called properly.
When using MinGW-w64 SEH variant, it behaves as expected (signal handler gets called).
I do not have clear idea of why this problem occurs, thus will be grateful if someone can give an explanation.

Does system() do a call like sem_post inside?

I think my code wouldn't print the text
oh why come here!\n
but it does.
Is there something 'wrong' with system()? Because, when I removed it, the code ran as I wanted, halting up.
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
pthread_t id0, id1;
sem_t sp;
void *fun0(void *) {
// When erasing the following line "system("");",
// it block up, and doesn't print "oh why come here!\n".
// But with it, it print the text!
system("");
return NULL;
}
void *fun1(void *) {
sem_wait(&sp);
fprintf(stderr, "oh why come here!\n");
return NULL;
}
int main() {
sem_init(&sp, 0, 0);
pthread_create(&id0, 0, fun0, NULL);
pthread_create(&id1, 0, fun1, NULL);
void *stat0, *stat1;
pthread_join(id0, &stat0);
pthread_join(id1, &stat1);
return 0;
}
Compiler: gcc 4.1.2
Linux kernel: 2.6.18
I compiled it with gcc 4.6.3, kernel 3.2.0, it ran as I want also.
So I think it is because of gcc 4.1.2 or kernel 2.6.18.
The system() call has nothing to do with it. My psychic powers tell me that sem_wait is failing with an error code instead of waiting—check the return value. For example, I can reproduce your results on Mac OS X, because on Mac OS X, sem_init() always fails with ENOSYS ("Function not implemented"), which causes the call to sem_wait to then fail with EBADF ("Bad file descriptor").
If you add some error checking, you'll see where things go awry:
if(sem_init(&sp, 0, 0) < 0)
fprintf(stderr, "sem_init failed: %s\n", strerror(errno));
...
if(sem_wait(&sp) < 0)
fprintf(stderr, "sem_wait failed: %s\n", strerror(errno));
You should also crank up the warning level on your compiler—I definitely recommend using -Wall, and -Wextra -pedantic if you want to catch a lot more possible problems. Currently, your code invokes undefined behavior by failing to return values from your fun0 and fun1 functions, which -Wall would warn you about. This kind of error may not cause any obvious problems on x86, but on other architectures such as IA64, uninitialized garbage can be deadly.
Problem of your code is with sem_wait(), from sem_wait man page, it says:
"sem_wait() decrements (locks) the semaphore pointed to by sem. If the semaphore's value is greater than zero, then the decrement proceeds, and the function returns, immediately. If the semaphore currently has the value zero, then the call blocks until either it becomes possible to perform the decrement (i.e., the semaphore value rises above zero), or a signal handler interrupts the call."
On your code you've initialized with sp with 0, when sem_wait() decrements, it blocks and never returns since there's no other thread increments sp variable.

What is the easiest way to make a C++ program crash?

I'm trying to make a Python program that interfaces with a different crashy process (that's out of my hands). Unfortunately the program I'm interfacing with doesn't even crash reliably! So I want to make a quick C++ program that crashes on purpose but I don't actually know the best and shortest way to do that, does anyone know what to put between my:
int main() {
crashyCodeGoesHere();
}
to make my C++ program crash reliably
The abort() function is probably your best bet. It's part of the C standard library, and is defined as "causing abnormal program termination" (e.g, a fatal error or crash).
Try:
raise(SIGSEGV); // simulates a standard crash when access invalid memory
// ie anything that can go wrong with pointers.
Found in:
#include <signal.h>
Dividing by zero will crash the application:
int main()
{
return 1 / 0;
}
*((unsigned int*)0) = 0xDEAD;
Well, are we on stackoverflow, or not?
for (long long int i = 0; ++i; (&i)[i] = i);
(Not guaranteed to crash by any standards, but neither are any of the suggested answers including the accepted one since SIGABRT could have been caught anyway. In practice, this will crash everywhere.)
throw 42;
Just the answer... :)
assert(false); is pretty good too.
According to ISO/IEC 9899:1999 it is guaranteed to crash when NDEBUG is not defined:
If NDEBUG is defined [...] the assert macro is defined simply as
#define assert(ignore) ((void)0)
The assert macro is redefined according to the current state of NDEBUG each time that is included.
[...]
The assert macro puts diagnostic tests into programs; [...] if expression (which shall have a scalar type) is false [...]. It
then calls the abort function.
Since a crash is a symptom of invoking undefined behaviour, and since invoking undefined behaviour can lead to anything, including a crash, I don't think you want to really crash your program, but just have it drop into a debugger. The most portable way to do so is probably abort().
While raise(SIGABRT) has the same effect, it is certainly more to write. Both ways however can be intercepted by installing a signal handler for SIGABRT. So depending on your situation, you might want/need to raise another signal. SIGFPE, SIGILL, SIGINT, SIGTERM or SIGSEGV might be the way to go, but they all can be intercepted.
When you can be unportable, your choices might be even broader, like using SIGBUS on linux.
The answer is platform specific and depends on your goals. But here's the Mozilla Javascript crash function, which I think illustrates a lot of the challenges to making this work:
static JS_NEVER_INLINE void
CrashInJS()
{
/*
* We write 123 here so that the machine code for this function is
* unique. Otherwise the linker, trying to be smart, might use the
* same code for CrashInJS and for some other function. That
* messes up the signature in minidumps.
*/
#if defined(WIN32)
/*
* We used to call DebugBreak() on Windows, but amazingly, it causes
* the MSVS 2010 debugger not to be able to recover a call stack.
*/
*((int *) NULL) = 123;
exit(3);
#elif defined(__APPLE__)
/*
* On Mac OS X, Breakpad ignores signals. Only real Mach exceptions are
* trapped.
*/
*((int *) NULL) = 123; /* To continue from here in GDB: "return" then "continue". */
raise(SIGABRT); /* In case above statement gets nixed by the optimizer. */
#else
raise(SIGABRT); /* To continue from here in GDB: "signal 0". */
#endif
}
The only flash I had is abort() function:
It aborts the process with an abnormal program termination.It generates the SIGABRT signal, which by default causes the program to terminate returning an unsuccessful termination error code to the host environment.The program is terminated without executing destructors for objects of automatic or static storage duration, and without calling any atexit( which is called by exit() before the program terminates)function. It never returns to its caller.
I see there are many answers posted here that will fall into lucky cases to get the job done, but none of them are 100% deterministic to crash. Some will crash on one hardware and OS, the others would not.
However, there is a standard way as per official C++ standard to make it crash.
Quoting from C++ Standard ISO/IEC 14882 §15.1-7:
If the exception handling mechanism, after completing the
initialization of the exception object but before the activation of a
handler for the exception, calls a function that exits via an
exception, std::terminate is called (15.5.1).
struct C {
C() { }
C(const C&) {
if (std::uncaught_exceptions()) {
throw 0; // throw during copy to handler’s exception-declaration object (15.3)
}
}
};
int main() {
try {
throw C(); // calls std::terminate() if construction of the handler’s
// exception-declaration object is not elided (12.8)
} catch(C) { }
}
I have written a small code to demonstrate this and can be found and tried on Ideone here.
class MyClass{
public:
~MyClass() throw(int) { throw 0;}
};
int main() {
try {
MyClass myobj; // its destructor will cause an exception
// This is another exception along with exception due to destructor of myobj and will cause app to terminate
throw 1; // It could be some function call which can result in exception.
}
catch(...)
{
std::cout<<"Exception catched"<<endl;
}
return 0;
}
ISO/IEC 14882 §15.1/9 mentions throw without try block resulting in implicit call to abort:
If no exception is presently being handled, executing a
throw-expression with no operand calls std::terminate()
Others include :
throw from destructor: ISO/IEC 14882 §15.2/3
*( ( char* ) NULL ) = 0;
This will produce a segmentation fault.
This one is missing:
int main = 42;
This crashes on my Linux system, because string literals are stored in read only memory:
0[""]--;
By the way, g++ refuses to compile this. Compilers are getting smarter and smarter :)
What about stack overflow by a dead loop recursive method call?
#include <windows.h>
#include <stdio.h>
void main()
{
StackOverflow(0);
}
void StackOverflow(int depth)
{
char blockdata[10000];
printf("Overflow: %d\n", depth);
StackOverflow(depth+1);
}
See Original example on Microsoft KB
This is a more guaranteed version of abort presented in above answers.It takes care of the situation when sigabrt is blocked.You can infact use any signal instead of abort that has the default action of crashing the program.
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
sigset_t act;
sigemptyset(&act);
sigfillset(&act);
sigprocmask(SIG_UNBLOCK,&act,NULL);
abort();
}
This is the snippet provided by Google in Breakpad.
volatile int* a = reinterpret_cast<volatile int*>(NULL);
*a = 1;
int i = 1 / 0;
Your compiler will probably warn you about this, but it compiles just fine under GCC 4.4.3
This will probably cause a SIGFPE (floating-point exception), which perhaps is not as likely in a real application as SIGSEGV (memory segmentation violation) as the other answers cause, but it's still a crash. In my opinion, this is much more readable.
Another way, if we're going to cheat and use signal.h, is:
#include <signal.h>
int main() {
raise(SIGKILL);
}
This is guaranteed to kill the subprocess, to contrast with SIGSEGV.
int* p=0;
*p=0;
This should crash too. On Windows it crashes with AccessViolation and it should do the same on all OS-es I guess.
Although this question already has an accepted answer...
void main(){
throw 1;
}
Or... void main(){throw 1;}
int main(int argc, char *argv[])
{
char *buf=NULL;buf[0]=0;
return 0;
}
Writing to a read-only memory will cause segmentation fault unless your system don't support read-only memory blocks.
int main() {
(int&)main = 0;
}
I have tested it with MingGW 5.3.0 on Windows 7 and GCC on Linux Mint. I suppose that other compilers and systems will give a similar effect.
Or another way since we're on the band wagon.
A lovely piece of infinite recursion. Guaranteed to blow your stack.
int main(int argv, char* argc)
{
return main(argv, argc)
}
Prints out:
Segmentation fault (core dumped)
void main()
{
int *aNumber = (int*) malloc(sizeof(int));
int j = 10;
for(int i = 2; i <= j; ++i)
{
aNumber = (int*) realloc(aNumber, sizeof(int) * i);
j += 10;
}
}
Hope this crashes. Cheers.
int main()
{
int *p=3;
int s;
while(1) {
s=*p;
p++;
}
}
A stylish way of doing this is a pure virtual function call:
class Base;
void func(Base*);
class Base
{
public:
virtual void f() = 0;
Base()
{
func(this);
}
};
class Derived : Base
{
virtual void f()
{
}
};
void func(Base* p)
{
p->f();
}
int main()
{
Derived d;
}
Compiled with gcc, this prints:
pure virtual method called
terminate called without an active exception
Aborted (core dumped)
You can use of assembly in your c++ code BUT INT 3 is only for x86 systems other systems may have other trap/breakpoint instructions.
int main()
{
__asm int 3;
return 0;
}
INT 3 causes an interrupt and calls an interrupt vector set up by the OS.
Use __builtin_trap() in GCC or clang, or __debugbreak() in MSVC. Not handling these breakpoints/traps will lead to an unhandled breakpoint exception/crash.
Other suggestions that use abort() or exit(): those may be handled by other threads, making it more difficult to see the stack of the thread that propagated the crash.
#include <thread>
void intentionalCrash()
{
auto noop = [](){return;};
// Thread t1 is in a joinable state.
// When program returns t1 will be out of scope.
// Destructing a joinable thread creates a crash.
std::thread t1(noop);
}
int main()
{
intentionalCrash();
return 0;
}
Simple buffer overflow code that will cause the program to crash
int main()
{
int n[0];
n[2] = 0;
}

Porting VC++'s __try/__except EXCEPTION_STACK_OVERFLOW to MinGW

I am trying to port some code using VC++'s try-except statement to MinGW:
bool success = true;
__try {
//...
} __except ((EXCEPTION_STACK_OVERFLOW == GetExceptionCode())
? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH) {
success = false;
_resetstkoflw();
}
return success;
Is it possible to write code that catches a stack overflow exception using MinGW g++?
You would need to manually call the Windows API functions which register exception handling; namely, AddVectoredExceptionHandler. Note that by using MinGW which does not respect SEH exceptions, throwing any SEH exception or attempting to catch any such exception will result in undefined behavior, because the normal C++ stack unwinding semantic isn't done. (How does Windows know to nuke all those std::strings on the stack?)
You would also need to call RemoveVectoredExceptionHandler at the end of the time you want that SEH exception handler to be called.
Generally MinGW is lacking in support of Windows features like SEH and COM. Any reason you're trying to use that instead of MSVC++ (given that both compilers are free?)
This isn't well known, but the header file <excpt.h> in MinGW and MinGW-w64 provides macros __try1 and __except1 to produce gcc inline assembly for handling exceptions. These macros are not documented and are not easy to use. It gets worse. The x86_64 editions of __try1 and __except1 aren't compatible with the 32-bit editions. They use different callbacks with different arguments and different return values.
After a few hours, I almost had working code on x86_64. I needed to declare a callback with the same prototype as _gnu_exception_handler in MinGW's runtime. My callback was
long CALLBACK
ehandler(EXCEPTION_POINTERS *pointers)
{
switch (pointers->ExceptionRecord->ExceptionCode) {
case EXCEPTION_STACK_OVERFLOW:
return EXCEPTION_EXECUTE_HANDLER;
default:
return EXCEPTION_CONTINUE_SEARCH;
}
}
And my try-except code was
__try1 (ehandler) {
sum = sum1to(n);
__asm__ goto ( "jmp %l[ok]\n" :::: ok);
} __except1 {
printf("Stack overflow!\n");
return 1;
}
ok:
printf("The sum from 1 to %u is %u\n", n, sum);
return 0;
It was working until I enabled optimization with gcc -O2. This caused assembler errors so my program no longer compiled. The __try1 and __except1 macros are broken by an optimization in gcc 5.0.2 that moves functions from .text to a different section.
When the macros did work, the control flow was stupid. If a stack overflow happened, the program jumped through __except1. If a stack overflow didn't happen, the program fell through __except1 to the same place. I needed my weird __asm__ goto to jump to ok: and prevent the fall-through. I can't use goto ok; because gcc would delete __except1 for being unreachable.
After a few more hours, I fixed my program. I copied and modified the assembly code to improve the control flow (no more jump to ok:) and to survive gcc -O2 optimization. This code is ugly, but it works for me:
/* gcc except-so.c -o except-so */
#include <windows.h>
#include <excpt.h>
#include <stdio.h>
#ifndef __x86_64__
#error This program requires x86_64
#endif
/* This function can overflow the call stack. */
unsigned int
sum1to(unsigned int n)
{
if (n == 0)
return 0;
else {
volatile unsigned int m = sum1to(n - 1);
return m + n;
}
}
long CALLBACK
ehandler(EXCEPTION_POINTERS *pointers)
{
switch (pointers->ExceptionRecord->ExceptionCode) {
case EXCEPTION_STACK_OVERFLOW:
return EXCEPTION_EXECUTE_HANDLER;
default:
return EXCEPTION_CONTINUE_SEARCH;
}
}
int main(int, char **) __attribute__ ((section (".text.startup")));
/*
* Sum the numbers from 1 to the argument.
*/
int
main(int argc, char **argv) {
unsigned int n, sum;
char c;
if (argc != 2 || sscanf(argv[1], "%u %c", &n, &c) != 1) {
printf("Argument must be a number!\n");
return 1;
}
__asm__ goto (
".seh_handler __C_specific_handler, #except\n\t"
".seh_handlerdata\n\t"
".long 1\n\t"
".rva .l_startw, .l_endw, ehandler, .l_exceptw\n\t"
".section .text.startup, \"x\"\n"
".l_startw:"
:::: except );
sum = sum1to(n);
__asm__ (".l_endw:");
printf("The sum from 1 to %u is %u\n", n, sum);
return 0;
except:
__asm__ (".l_exceptw:");
printf("Stack overflow!\n");
return 1;
}
You might wonder how Windows can call ehandler() on a full stack. All those recursive calls to sum1to() must remain on the stack until my handler decides what to do. There is some magic in the Windows kernel; when it reports a stack overflow, it also maps an extra page of stack so that ntdll.exe can call my handler. I can see this in gdb, if I put a breakpoint on my handler. The stack grows down to address 0x54000 on my machine. The stack frames from sum1to() stop at 0x54000, but the exception handler runs on an extra page of stack from 0x53000 to 0x54000. Unix signals have no such magic, which is why Unix programs need sigaltstack() to handle a stack overflow.
You might want to look into LibSEH for adding Structured Exception Handling compatibility for MinGW.
MinGW doesn't support the keywords for structured exceptions; but, as Billy O'Neal says in his answer, you can call certain native functions to get the same effect.
The question is whether you want the same effect. I strongly believe that structured exceptions are a mistake. The list of structured exceptions that the operating system will tell you about include things like "tried to divide an integer by 0," "couldn't use the HANDLE parameter passed to a function," "tried to execute an illegal machine code instruction," and "tried to access memory without permission to do so." You really can't do anything intelligent about these errors, but structured exceptions give you the opportunity to (1) claim that you have and (2) allow the program to hobble along a little longer. It's far better to find out why the code tried to divide by 0, passed an invalid HANDLE parameter, tried to access memory without permission to do so, etc. and fix the code to never do that.
There is an argument that you could use structured exceptions to detect problems, display a dialog box, and exit. I'm not sure how this is better than letting the operating system display a dialog box and exit the program (especially if the operating system sends you a minidump in the process), which is the default behavior for unhandled exceptions.
Some errors aren't recoverable.