5

I'm looking at modifying the MS structured exception-to-exception mapping code we have to use the new C++11 error_code/error_condition/exception mechanisim.

My understanding is that the general philosiphy is that you should try to map your error codes to std::error_condition codes first, failing that, make your own custom error_condition codes.

The issue I'm seeing that the std::errc is pretty much tailored to work well with POSIX errors. If I'm getting codes from a source that has a fairly differernt error universe than your typical OS call, it just doesn't map well.

For example, lets take Microsoft's SEH codes. These come from the OS, so in theory it should map as well as about anything outside POSIX can. But it sure doesn't seem to map well at all:

EXCEPTION_ACCESS_VIOLATION  = permission_denied
EXCEPTION_ARRAY_BOUNDS_EXCEEDED = argument_out_of_domain perhaps?
EXCEPTION_BREAKPOINT = ?
EXCEPTION_DATATYPE_MISALIGNMENT = ?
EXCEPTION_FLT_DENORMAL_OPERAND = ? 
EXCEPTION_FLT_DIVIDE_BY_ZERO = ?
EXCEPTION_FLT_INEXACT_RESULT = ? 
EXCEPTION_FLT_INVALID_OPERATION = ?
EXCEPTION_FLT_OVERFLOW = ?
EXCEPTION_FLT_STACK_CHECK = ?
EXCEPTION_FLT_UNDERFLOW = ?
EXCEPTION_GUARD_PAGE = ?
EXCEPTION_ILLEGAL_INSTRUCTION = ?
EXCEPTION_IN_PAGE_ERROR = ?
EXCEPTION_INT_DIVIDE_BY_ZERO = ?
EXCEPTION_INT_OVERFLOW = value_too_large perhaps, but then what do I use for _STACK_OVERFLOW?
EXCEPTION_INVALID_DISPOSITION = ?
EXCEPTION_INVALID_HANDLE = ? 
EXCEPTION_NONCONTINUABLE_EXCEPTION = ? 
EXCEPTION_PRIV_INSTRUCTION = ?
EXCEPTION_SINGLE_STEP = ?
EXCEPTION_STACK_OVERFLOW = value_too_large perhaps, but then what do I use for _INT_OVERFLOW?

So what would the best way to attack this?

T.E.D.
  • 44,016
  • 10
  • 73
  • 134
  • 1
    It is exceedingly dangerous to attempt to handle most of these. For example, if an access violation occurs or an illegal instruction is encountered, your program is hopelessly broken. For most of these, the best way to handle the exception is not to handle it at all (and let the application terminate). Certainly, mapping an AV to permission_denied is not at all a good idea. Most programs should not need to handle structured exceptions (there are a select few scenarios where it might be useful to try to handle a structured exception, but these scenarios are very rare). – James McNellis Oct 26 '12 at 20:00
  • @JamesMcNellis - I believe all we do now when a SEH exception occurrs is spit out an appropriate error message and then shut down the thread as nicely as possible. We have a large application that does a lot of complex math coded by lots of different module groups, so it has been very helpful to us to be able to spit out what kind of floating-point error caused a crash, and perhaps what line it occurred on, before death. – T.E.D. Oct 26 '12 at 20:03
  • 2
    @T.E.D.: I've always wondered about this, and it seems the key is to make a new `error_category` class, but I don't know if I should make an instance or a derived type or how to use it or anything :/ EDIT: I found a tutorial! http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-1.html – Mooing Duck Oct 26 '12 at 20:12
  • @MooingDuck - I've been working off that very nice 5-part article myself. Great, isn't it? – T.E.D. Oct 26 '12 at 20:19

1 Answers1

2

First as commented by @JamesMcNellis some of this exceptions are very dangerous and it may be better to let OS handle them and terminate your program, since those errors are usually an error in your code. But may be you want to handle them and write something like a crash report possibly with a dump of stack and registers.

Beside that std::error_condition and std::error_code is not designed to only work with POSIX errors. Their structure is designed in a way that can handle any case that an int value that is equal to 0 indicate a success and otherwise an error, so you may write a completely valid code that use them with std::error_code and std::error_condition but you should drive a class from std::error_category and implement its virtual functions to provide explanation of your error codes that matched with your error codes(in your case NT status codes):

class NT_status_code_error_category : std::error_category {
public:
    const char* name() const {return "NT status code";}
    std::string message( int errCode ) const {
        switch( errCode ) {
        case EXCEPTION_ACCESS_VIOLATION: return "Access violation";
        // a couple of other error codes will be handled here
        default: return "Unknown status code";
        }
    }
    std::error_condition default_error_condition( int errCode ) const {
    return std::error_condition( errCode, *this );
}
};
inline NT_status_code_error_category const& NT_status_code_category() {
    static NT_status_code_error_category res;
    return res;
}

inline std::error_code make_NT_status_error_code( int status ) {
    return std::error_code( status, NT_status_code_category() );
}
inline std::error_condition make_NT_status_error_condition( int status ) {
    return std::error_condition( status, NT_status_code_category() );
}
BigBoss
  • 6,904
  • 2
  • 23
  • 38
  • OK. But it is reasonable in my case to make my own error conditions along with my error codes? For example, the only difference in handling I will probably ever have is if it is a floating point error vs. non-floating point. (even then, the difference may just be embedded in the error messages - `message()`). – T.E.D. Oct 29 '12 at 16:13
  • I think as you already said in your question, Microsoft SEH come from OS and just like any other error codes, they should mapped to `std::error_code`, so if it is logical, to have an `error_condition` for `POSIX` or `Win32` error codes, I think it worth to have an `error_condition` for `SEH` codes – BigBoss Oct 29 '12 at 18:38