0

Why standard C++ doesn't respect system (foreign or hardware) exceptions?

E.g. when null pointer dereference occurs, stack isn't unwound, destructors aren't called, and RAII doesn't work.

The common advice is "to use system API". But on certain systems, specifically Win32, this doesn't work. To enable stack unwinding for this C++ code

// class Foo;
// void bar(const Foo&);
bar(Foo(1, 2));

one should generate something like this C code

Foo tempFoo;
Foo_ctor(&tempFoo);
__try {
    bar(&tempFoo);
}
__finally {
    Foo_dtor(&tempFoo);
}
Foo_dtor(&tempFoo);

and it's impossible to implement this as C++ library.


Upd: Standard doesn't forbid handling system exceptions. But it seems that popular compilers like g++ doesn't respect system exceptions on any platforms just because standard doesn't require this.

The only thing that I want - is to use RAII to make code readable and program reliable. I don't want to put hand-crafted try\finally around every call to unknown code. For example in this reusable code, AbstractA::foo is such unknown code:

void func(AbstractA* a, AbstractB* b) {
    TempFile file;
    a->foo(b, file);
}

Maybe one will pass to func such implementation of AbstractA, which every Friday will not check if b is NULL, so access violation will happen, application will terminate and temporary file will not be deleted. How many months uses will suffer because of this issue, until either author of func or author of AbstractA will do something with it?


Related: Is `catch(...) { throw; }` a bad practice?

Abyx
  • 1,455

3 Answers3

5

The C++ standard doesn't respect system exceptions because it was designed to be usable on a wide range of platforms (much wider that PC-based platforms). It would be impossible to provide some sort of support for each of the platform in the standard. This is left for implementations and rightfully so.

My reaction to the rant part of your question: Win32 exceptions are thrown in fatal cases from which you can't really recover. __try & friends does work in C++ as well (not only for C), and you can manually call the destructor if you need to (but your program is in a state where it won't run anymore, so unless that destructor releases something the OS wouldn't normally release after the process terminated, there isn't much point).

Edit: In answer to your update: You are still ranting. It's not how you imagined it, so what? You can still protect yourself against the scenario you cited as an example. You use the platform-specific code to catch the system exception, close the file and crash gracefully. There might be a better way to do this; ask a specific question on SO. Isolating 3rd party code is not trivial and likely requires some effort to achieve (a good example of this is the famously unstable flash plugin which now runs isolated in most major browsers).

g++ doesn't respect system exceptions on any platforms just because standard doesn't require this

Even though it does implement a good number of extensions, gcc targets architectures, not platforms. Gcc itself is ported to different platforms but that's a different story; the code-generation part is architecture-dependent, not platform-dependent. This explains why it wouldn't be possible to support windows system exceptions without great effort.

  • Why not to use system exceptions wherever it's possible, instead of not to use them at all? – Abyx Dec 07 '11 at 15:10
  • @Abyx: Then it's implementation defined, and thus not standard C++. In fact, since behaviour is undefined in most (or even all?) error conditions like null pointer dereference, every implementation is free to do something like that. If they don't, perhaps they agree with my gut feeling that your code is screwed anyway if such errors occur, and it's likely because your code is broken. –  Dec 07 '11 at 15:17
  • "Win32 exceptions are thrown in fatal cases from which you can't really recover" - it's incorrect. In VC++ all exceptions are implemented as system exceptions, and they definitely are non-fatal. Also, memory access violation can be non-fatal exceptions, nothing fatal will happen if replace if (p) with try block. – Abyx Dec 07 '11 at 15:22
  • @delnan why my code? It can be third party dynamically linked code (plugin). – Abyx Dec 07 '11 at 15:25
  • 2
    @Abyx: They can be non-fatal, but in reality, they virtually always are. You need to process isolate third-party code if you wan to be protected from them. – DeadMG Dec 07 '11 at 15:29
  • @DeadMG, there is nothing fatal with null pointer dereference - it doesn't mean that data are corrupted, or another really bad thing happen. – Abyx Dec 07 '11 at 16:01
  • "You are still ranting. It's not how you imagined it, so what?" - no, I know that almost all *nix programmers don't understand what is SEH for. However Windows VC++\Delphi programmers who use try block for dealing with third-party closed-source code don't understand how to leave without it. – Abyx Dec 07 '11 at 18:33
  • Delphi targets windows exclusively. It's natural that it supports system exceptions. – Tamás Szelei Dec 08 '11 at 11:36
  • @Abyx null pointer dereferences mean that your program almost certainly doesn't do what you thought it did. C++ just makes that incredibly wide, because undefined behaviour isn't one statement is unpredictable, it's the whole program before and after can do anything at all – Caleth Jul 29 '22 at 09:42
3

You can configure MSVC to catch system exceptions in a catch(...) block. This is exactly as the Standard intended- implementations provide mechanisms to catch errors thrown by their implementations. Strictly speaking, it's just UB and they don't have to provide any mechanism.

However, there's an increasing trend, both within and outside Microsoft, to not defensively code- for example IsBadXXXPtR is now heavily discouraged.

Glorfindel
  • 3,137
DeadMG
  • 36,902
  • And there even is a function in the Microsoft CRT that allows you to convert system exceptions to C++ exceptions: http://msdn.microsoft.com/en-us/library/5z4bw5h5.aspx – Patrick Dec 07 '11 at 15:32
  • There is no problem with MSVC, but I want to use g++ and other compilers, which doesn't support SEH on Windows. – Abyx Dec 07 '11 at 15:58
  • @Patrick, this function works only for MSVC. – Abyx Dec 07 '11 at 16:12
  • And I'm not talking about catch, I'm about RAII. – Abyx Dec 07 '11 at 16:12
  • 2
    @Abyx: It's not the Standard's fault that the implementation is deficient. Also, MSVC does call destructors when system exceptions are caught with catch(...). – DeadMG Dec 08 '11 at 06:44
1

As a C++ programmer I am glad that hardware exceptions are completely different things.

Imagine if they were not. Suddenly, code that has no throw statements in it is now throwing an exception. It might even be coming from inside a function which is declared as throw() or nothrow.

Besides that, in order to handle these exceptions properly, the programmer must know the hardware and platform quite well. In that case, he may as well use the platform provided functions to handle it. Just writing a catch block does not come anywhere close to properly fixing a bad pointer reference or a division-by-zero.

Zan Lynx
  • 1,300
  • throw() works in run-time, so it's not an issue. nothrow works in compile-time, so yes, with hardware exceptions we can't use it. Regarding to complexity, just imagine that x->y works as x ? x->y : throw_null_pointer_dereference() – Abyx Jun 08 '12 at 01:47
  • 2
    @Abyx: And remember that stack overflow works like 2+4; if (stackLeft<0) throw stack_overflow(). Each and every expression might overflow the stack. – MSalters Jan 26 '15 at 15:09