diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2016-06-02 15:46:17 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2016-06-02 15:46:17 -0700 |
commit | 5b5ef63b934bc49a46fc654ac8bfcd3142c73f6f (patch) | |
tree | 8b13f0b10585897ebd9eadae65dfa3d2625506e5 | |
parent | c58e23683c2abbd368f06ef664a9341305b3a63c (diff) | |
download | mu-5b5ef63b934bc49a46fc654ac8bfcd3142c73f6f.tar.gz |
3031 - better integer overflow protection
This improves on commit 3026; it turns out you need to manually handle the traps generated by -ftrapv. https://gist.github.com/mastbaum/1004768 Signal handling is based on https://spin.atomicobject.com/2013/01/13/exceptions-stack-traces-c. Various combinations of platform+compiler seem to work very differently: gcc everywhere seems to have extremely threadbare ftrapv support Clang + OSX generates SIGILL. Clang + Linux is advertised to generate SIGABRT, so I handle that out of an excess of caution. However, in my experience it seems to kill the program (sometimes segfaulting) even without any signal handlers installed. In the process, I realized that all my current builds are using Clang, so I added one little test on CI to use g++ in commit 3029.
-rw-r--r-- | 001help.cc | 69 |
1 files changed, 68 insertions, 1 deletions
diff --git a/001help.cc b/001help.cc index d6fa6d25..63be194f 100644 --- a/001help.cc +++ b/001help.cc @@ -97,7 +97,74 @@ bool is_equal(char* s, const char* lit) { #define SIZE(X) (assert((X).size() < (1LL<<(sizeof(int)*8-2))), static_cast<int>((X).size())) //: 5. Integer overflow is guarded against at runtime using the -ftrapv flag -//: to the compiler, supported by both GCC and LLVM. +//: to the compiler, supported by Clang (GCC version only works sometimes: +//: http://stackoverflow.com/questions/20851061/how-to-make-gcc-ftrapv-work). +:(before "atexit(teardown)") +initialize_signal_handlers(); // not always necessary, but doesn't hurt +//? cerr << INT_MAX+1 << '\n'; // test overflow +//? assert(false); // test SIGABRT +:(code) +// based on https://spin.atomicobject.com/2013/01/13/exceptions-stack-traces-c +void initialize_signal_handlers() { + struct sigaction action; + action.sa_sigaction = dump_and_exit; + sigemptyset(&action.sa_mask); + sigaction(SIGABRT, &action, NULL); // assert() failure or integer overflow on linux (with -ftrapv) + sigaction(SIGILL, &action, NULL); // integer overflow on OS X (with -ftrapv) + sigaction(SIGFPE, &action, NULL); // floating-point overflow and underflow +} +void dump_and_exit(int sig, siginfo_t* siginfo, unused void* dummy) { + switch (sig) { + case SIGABRT: + #ifndef __APPLE__ + cerr << "SIGABRT: might be an integer overflow if it wasn't an assert() failure\n"; + _Exit(1); + #endif + break; + case SIGILL: + #ifdef __APPLE__ + cerr << "SIGILL: most likely caused by integer overflow\n"; + _Exit(1); + #endif + break; + case SIGFPE: + switch(siginfo->si_code) + { + case FPE_INTDIV: + cerr << "SIGFPE: (integer divide by zero)\n"; + break; + case FPE_INTOVF: + cerr << "SIGFPE: (integer overflow)\n"; // dormant; requires hardware support + break; + case FPE_FLTDIV: + cerr << "SIGFPE: (floating-point divide by zero)\n"; + break; + case FPE_FLTOVF: + cerr << "SIGFPE: (floating-point overflow)\n"; + break; + case FPE_FLTUND: + cerr << "SIGFPE: (floating-point underflow)\n"; + break; + case FPE_FLTRES: + cerr << "SIGFPE: (floating-point inexact result)\n"; + break; + case FPE_FLTINV: + cerr << "SIGFPE: (floating-point invalid operation)\n"; + break; + case FPE_FLTSUB: + cerr << "SIGFPE: (subscript out of range)\n"; + break; + default: + cerr << "SIGFPE: arithmetic exception\n"; + break; + } + _Exit(1); + default: + break; + } +} +:(before "End Includes") +#include <signal.h> //: 6. Map's operator[] being non-const is fucking evil. :(before "Globals") // can't generate prototypes for these |