views:

104

answers:

6

Following fails to catch a exception

int *i;  //intentionally uninitialized

try {
      *i = 6;
    }
catch (const runtime_error e) {
      cout << "caught!" << endl;
    }

is it actually catching a runtime error or an exception?

+4  A: 

The line *i = 6; does not throw a runtime_error; it results in undefined behavior.

The uninitialized pointer will be dereferenced and your program will try to write the value six to wherever it points (if it points anywhere). This results in undefined behavior. In most cases, this means your program will either crash immediately or will crash later on because you will have corrupted something important in memory.

There is no way to "catch" this sort of error as an exception in standard C++; you need to write your code such that you don't do things like this.

James McNellis
+1  A: 

This is not a runtime error, it is undefined runtime behaviour due to a compile time error.

To catch it (and many others like it), set your compiler to the highest warning level possible. (As compilers, contrary to Martin's comment, do check if you are stupid if you let them.) gcc -Wall would have done it in this case:

$ g++ -Wall test.cpp 
test.cpp: In function ‘int main()’:
test.cpp:<line>: warning: ‘i’ is used uninitialized in this function

Personally, I prefer something along these lines:

$ CXXWARN="-Wall -Wextra -Werror -pedantic -Wno-unused-parameter \
         -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings \
         -Wmissing-declarations -Wredundant-decls -Winline"
$ g++ $CXXWARN test.cpp

Your mileage may vary.

DevSolar
I'm not sure "compile time error" is a good (much less accepted) phrase for "programmer error." The error occurred before the compiler was run.
Potatoswatter
All errors are programmer errors of some kind. Runtime errors are also encoded before the compiler was run. It's more about when the error could be *caught*. The phrase "compile time error" (or "compiler error") was used comfortably in all teams I've worked in so far, as was "link time error".
DevSolar
@Dev: This is a compile time error: `int d,d;`. Programmer error is a much better term for saying "their fault." Where the error occurs is a compile error, link error, runtime error, etc, but all of those are programmer errors (except the last, which can be a user error)
GMan
@DevSolar: A compiler error is something else entirely: when the compiler does the wrong thing with correct code. Compiler errors are no fun.
Potatoswatter
+2  A: 

Disclaimer

This kind of thing is no good except for debugging. There aren't many legitimate reasons to continue your program after a memory access exception, because usually it indicates data corruption.

That said, I think it's better to answer the question than to pass judgment, censure, or censor it.


The C++ classes derived from exception are simply conveniences to encourage good practice among programmers. They have no special semantics, and aren't differentiated in anything but name.

Worse, C++ exceptions cannot pass outside a signal handler (what in other languages would be called the "exception handler," the function which is called upon the illegal access). The standard has a specific warning about this,

A [plain old function] that could be used as a signal handler in a conforming C program does not produce undefined behavior when used as a signal handler in a C++ program. The behavior of any other function used as a signal handler in a C++ pro- gram is implementation defined.213)

213) In particular, a signal handler using exception handling is very likely to have problems

That said, if you want to catch this, use the UNIX signal facility to install a function that does not use C++ features.

#include <csignal>
#include <cstdlib>
#include <cstdio>

void catch_memory( int ) {
    std::printf( "caught!\n" );
    std::abort();
}

int main() {
    std::signal( SIGSEGV, catch_memory );

    int *i = 0;
    *i = 6;
}
Potatoswatter
Erm... I think you are 1) missing the point of the OP, who is expecting an exception to happen for something that is UB, and 2) mixing up signal handlers (the functions registered with `signal()` to handle signals triggered by the environment or uses of the `raise()` function) and exception handlers (i.e. `catch` blocks).The access on an uninitialized pointer is *undefined behaviour*. Registering a signal handler for SIGSEGV might or might not help, because what will happen is *undefined*.
DevSolar
@Dev: No, the OP is expecting the C++ exception facility to do something that other languages' exception facilities do. The C++ standard does not define what happens upon `NULL` dereference, **but other applicable specifications may**.
Potatoswatter
The problem is the uninitialized access. The solution is compiler warnings to fix the root cause. You cannot write a signal handler for SIGSEGV that would allow the program to continue running. Even saving your data and shutting down cleanly would rely on your optimism that none of the in-memory data structures has been corrupted already. I'd call that "barking up the wrong tree".
DevSolar
@DevSolar: The compiler cannot catch all uninitialized accesses! OP's code is an example. An illustration. In fact, there are programs out there (not well written ones, IMHO) that do catch SIGSEGV and continue on their merry way.
Potatoswatter
Yup. A surprising many programs out there rely on undefined behaviour. That doesn't change the fact that I consider such code to be utterly broken.
DevSolar
@DevSolar: See my disclaimer. There are exceptions to every rule. One is for debugging, where effectively portability may be moot. Another is if the program gives the user low-level access to the machine, such as an interpreted language with pointers. Graceful exits from such are a must-have feature.
Potatoswatter
The disclaimer was an excellent idea. Downvote removed.
DevSolar
+1  A: 

Appropriate catch clause gets executed when an appropriate exception is thrown using the C++ throw keyword. These are C++ exceptions.

What you get with the OP code is probably a system generated exception (not C++ exception) and strictly it is an undefined behavior.

Chubsdad
A: 

It does not throw exception. It could lead to crash. If you are working in a project, first thing is, get it reviewed by your peers. Code reviews are very helpful most of the time. If not, you can catch such bugs early in the development cycle by doing using static code analysis tools like Klocwork and Dynamic code analysis tools like Purify, Bounds Checker etc.

bjskishore123
A: 

Microsoft created something called structured exceptions several years ago (a.k.a., SEH for "structured exception handling"). Although there is some similarity between C++ exceptions and structured exceptions, they are fundamentally different things. Personally, I've steered clear of SEH.

SEH allows you to, among other things, recognize when the stack has overflown or there has been a memory access violation. The thing is, there isn't much you can do in these cases: your program's state has been irretrievably broken before your handler gets a chance to run. And while you can't fix "irretrievably broken" your handler is allowed to claim it did (i.e., you can continue executing even though your stack has been smashed).

So your catch block isn't getting executed because the exception you're trying to catch is a Windows-specific extension that uses an entirely different system.

Max Lybbert