0
\$\begingroup\$

Whilst developing a bigger project, I was in need of having basic error handling inside the context of a C interface.

I came up with the following solution.

// include/interface/error.h
#ifndef SDK_INTERFACE_ERROR_H
#define SDK_INTERFACE_ERROR_H

#ifdef __cplusplus
extern "C" {
#endif //__cplusplus

struct Error;
typedef struct Error Error;

typedef void(*ErrorHandler)( Error const * );

void SetExceptionHandler( ErrorHandler const * inExceptionHandler );

[[ noreturn ]] void ThrowException( Error const * inError );

#ifdef __cplusplus
}
#endif //__cplusplus
#endif //SDK_INTERFACE_ERROR_H
// source/interface/error.cpp
#include "interface/error.h"

#include <shared_mutex>
#include <mutex>
#include <cstdlib>
#include <functional>

namespace
{
    std::function< void( Error const * ) > sErrorHandler = []( Error const * ){ std::abort(); };
    std::shared_mutex sErrorHandlerMutex;
}

void
SetExceptionHandler( ErrorHandler const * inExceptionHandler )
{
    std::unique_lock lock( sErrorHandlerMutex );
    sErrorHandler = *inExceptionHandler;
}

void
ThrowException( Error const * inError )
{
    std::shared_lock lock( sErrorHandlerMutex );
    sErrorHandler( inError );
    std::abort();
}

Errors in this context means unrecoverable errors, So error handling is simply a means to provide a user of this interface time to perform a clean exit.

However I still have the following questions

  • General Code review
  • Would it be safe to throw an exception inside an ErrorHandler, which could then be caught again outside the interface
  • Is it safe to pass stack addresses to ThrowException
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Code Review:

That's not a very unique header guard!

#ifndef SDK_INTERFACE_ERROR_H
#define SDK_INTERFACE_ERROR_H

In this section the code has to be valid in both C and C++. I have not used C in a long time but is [[ noreturn ]] part of C now?

[[ noreturn ]] void ThrowException( Error const * inError );

Would it be safe to throw an exception inside an ErrorHandler

It looks like this can be called from C code. C does not know anything about C++ or exceptions. So there is no guarantee in the standard of C that exceptions will correctly propagate across any C interface. So technically NO it is not safe, you are well into at least compiler defined behavior.

In practice, it will depend on your compiler tool chain. You can probably validate its safety with sufficient unit/integration tests.


Is it safe to pass stack addresses to ThrowException

Depends on what you do with it.
But in the general sense yes that should be safe. If both sides C/C++ are using the same definition of Error and it is valid in both languages then yes it should work without any issues.

\$\endgroup\$
2
  • \$\begingroup\$ With the second question, I was more referring to a piece of C++ code registering an ErrorHandler which would throw an exception which could then be caught be another piece of C++ code. \$\endgroup\$ Commented Oct 5, 2023 at 11:09
  • \$\begingroup\$ @SamCoutteau As long as the stack unwinding does not unwind through a function call that is compiled by the C compiler (or declared extern "C" maybe) then you will be fine. \$\endgroup\$ Commented Oct 5, 2023 at 14:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.