MSVC has an option to trap NULL pointer exceptions and throw them in your program, which unfortunately tends to be abused. On Linux you get a SIGSEGV (segmentation fault), and the default handler core dumps.
The ideal solution would be to fix the code and have no bugs, but good luck with that :-) Especially with a large code base this is a big problem, it's better to get consistent, if erroneous, behaviour.
The way to get a NULL pointer exception on Linux was not very complicated, the two ingredients are an option for GCC, non-call-exceptions, and a signal handler for SIGSEGV. Since SIGSEGV is a synchronous signal this is perfectly safe, and it will look like a NULL dereference is causing the exception.
The code is quite short and easy to follow, as you can see I added two cases, the first try-catch will cause an NPE, which will be caught, while the second will cause a non-NULL segmentation fault, which our signal handler will handle the default way (a core dump). You could convert all segmentation faults to exceptions, but a non-NULL one is usually an indication of a much worse error.
Remember to compile this with the non-call-exceptions flag:
g++ main.cpp -g -lpthread -Wall -fnon-call-exceptions -O2 -o main
#include <stdio.h>
#include <unistd.h>
#ifndef _POSIX_SOURCE
#define _POSIX_SOURCE
#endif
#include <signal.h>
class NullPointerException
{
int data;
};
void signal_handler(int signum, siginfo_t *info, void *)
{
// info->si_addr holds the dereferenced pointer address
if (info->si_addr == NULL) {
// This will be thrown at the point in the code
// where the exception was caused.
throw NullPointerException();
} else {
// Now restore default behaviour for this signal,
// and send signal to self.
signal(signum, SIG_DFL);
kill(getpid(), signum);
}
}
int main(int argc, char **argv)
{
struct sigaction act; // Signal structure
act.sa_sigaction = signal_handler; // Set the action to our function.
sigemptyset(&act.sa_mask); // Initialise signal set.
act.sa_flags = SA_SIGINFO; // Our handler takes 3 params.
sigaction(11, &act, NULL); // Set signal action to our handler.
try {
int *a = NULL;
printf("%d\n", *a); // Cause Null Pointer Exception.
}
catch (...) {
printf("Exception caught!\n"); // It works!
}
try {
int *a = (int*)0x01;
printf("%d\n", *a); // Cause Null Pointer Exception.
}
catch (...) {
printf("Exception caught!\n"); // This should NOT be printed.
}
}
Edit: Found source.
Extremely nice! I will try to implement in ca2.
ReplyDeleteThank you for sharing!
It should deserve retribution...