0

Are there universal solutions to catch exceptions such as divide by zero, segmentation fault, etc. in compilers MSVC, GCC, Clang or universal wrapper for them, may be in "boost" library?

Surely must be a universal solution based on the nuances of each compiler. Even if I did write a similar solution under every compiler, I still can to leave and forget out any nuances. For example I can write in MSVC with SEH-exceptions and compile it with key: /ZHa

#include<iostream>
#include<string>

#ifdef _MSC_VER
#include <windows.h>
#include <eh.h>


class SE_Exception
{
private:
    EXCEPTION_RECORD m_er; 
    CONTEXT m_context; 
    unsigned int m_error_code;
public:
    SE_Exception(unsigned int u, PEXCEPTION_POINTERS pep) 
    {
        m_error_code = u;
        m_er = *pep->ExceptionRecord; 
        m_context = *pep->ContextRecord;
    }
    ~SE_Exception() {}
    unsigned int get_error_code() const { return m_error_code; }
    std::string get_error_str() const {
        switch(m_error_code) {
        case EXCEPTION_INT_DIVIDE_BY_ZERO: return std::string("INT DIVIDE BY ZERO");
        case EXCEPTION_INT_OVERFLOW:    return std::string("INT OVERFLOW");
        // And other 20 cases!!!

        }
        return std::string("UNKNOWN");
    }
};

void trans_func(unsigned int u, EXCEPTION_POINTERS* pExp)
{
    throw SE_Exception(u, pExp);
}

#else

struct SE_Exception
{
    unsigned int get_error_code() const { return 0; }
    std::string get_error_str() const { return std::string("Not MSVC compiler"); }
};
#endif

int main() {
#ifdef _MSC_VER
    _set_se_translator( trans_func );
#endif

    try {
        int a = 0;
        int b = 1 / a;
        std::cout << "b: " << b << std::endl;
    } catch(SE_Exception &e) {
        std::cout << "SEH exception: (" << e.get_error_code() << ") " << e.get_error_str() << std::endl;        
    } catch(...) {
        std::cout << "Unknown exception." << std::endl;        
    }

    int b;
    std::cin >> b;
    return 0;
}
Abhineet
  • 5,320
  • 1
  • 25
  • 43
Alex
  • 12,578
  • 15
  • 99
  • 195
  • 1
    Why not simply guard against diving by zero in the first place? – trojanfoe Jun 14 '13 at 10:31
  • 1
    Those "nuances" give very different behaviours: some platforms give you a special value (infinity or non-a-number), some raise a signal (not a C++ exception). Only Microsoft has this weird pseudo-exception mechanism. – Mike Seymour Jun 14 '13 at 10:43

1 Answers1

1

Division by zero and many other specific, hardware-related runtime errors (eg. invalid pointer dereference) are Undefined Behaviour, which means that the implementation is free to handle it in whatever way it wants.

Specifically for division by zero, overflows and other mathematical errors, see (emphasis mine):

5/4 [expr]

If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined. [ Note: most existing implementations of C ++ ignore integer overflows. Treatment of division by zero, forming a remainder using a zero divisor, and all floating point exceptions vary among machines, and is usually adjustable by a library function. — end note ]

5.6/4 [expr.mul]

The binary / operator yields the quotient, and the binary % operator yields the remainder from the division of the first expression by the second. If the second operand of / or % is zero the behavior is undefined.

Concerning null pointer dereferencing, see:

8.3.2/5 [dcl.ref]

in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the “object” obtained by dereferencing a null pointer, which causes undefined behavior.

Other specific errors are scattered throughout the Standard, I won't quote them all but you get the idea.


Since it is UB, there is no universal solution to handle it. Typically, MS Windows will propagate the error through SEH, Unix-like platforms will use signals, and other OSes may do even something else. And as noted in the quote above, it may even be possible to adjust the behaviour through implementation-dependent library calls.

The only real solution is to prevent these errors from happening in the first place, by inserting the relevant checks in your code.

Community
  • 1
  • 1
syam
  • 14,701
  • 3
  • 41
  • 65
  • While what you say is true, it is also true that under pretty much any non-embedded os and compiler combination, `signal.h` is the standard way of dealing with this sort of thing. – hexist Jun 14 '13 at 11:29
  • As I already replied in the comments to your answer, Windows/MSVC reports such errors (at least some of them) through SEH not signals. Anyway, could we keep this discussion in a single place, please? :) – syam Jun 14 '13 at 11:51