I am using a C library (which I also wrote) within a C++ program and I want to know how I should be doing error handling from within the C library such that the C++ program is able to decide how to handle errors that may happen.
I originally had the C library return a value indicating an error has occurred (e.g. NULL or -1) and just print an error message to stderr but this is not easily capturable by programs using the library.
Ideally I want the C++ program to be able to retrieve an error message string from the C library so that it can handle the error whichever way it wants to, such as logging the error message elsewhere.
Is there a common design idiom for this?
All methods, that require global state (errno, get_last_error, ...), will have concurrency issues. Using the return channel ruins return value optimization for you.
A common option is to take a pointer to an error struct as first or last parameter.
struct Error {
const char* message;
int code;
};
int my_nice_c_function( int a, int b, Error* err ) {
if ( err != NULL ) {
err->message = "";
err->code = 0;
}
return a + b;
}
When you pass them in from C++ it could look like:
Error err;
...
auto foo = my_nice_c_function( 5, 6, &err );
if ( err.code != 0 ) {
std::cerr << err.message << std::endl;
}
But make sure to always set the error members!
Related
I have inherited a (large) piece of code which has an error tracking mechanism where they pass in a boolean variable to all the methods they call and on errors at various stages of execution the method is stopped and returns, sometimes a default value.
Something like (BEFORE):
#include <iostream.h>
int fun1(int par1, bool& psuccess)
{
if(par1 == 42) return 43;
psuccess = false;
return -1;
}
int funtoo(int a, bool& psuccess)
{
int t = fun1(a, psuccess);
if(!psuccess)
{
return -1;
}
return 42;
}
void funthree(int b, bool& psuccess)
{
int h = funtoo(b, psuccess);
if(!psuccess)
{
return;
}
cout << "Yuppi" << b;
}
int main()
{
bool success = true;
funthree(43, success);
if(!success)
{
cout<< "Life, universe and everything have no meaning";
}
}
Please note, that this is a mixture of C and C++ code, exactly the way the project is in.
Now, comes a piece of C magic: "someone" somewhere defined a macro:
#define SUCCES_OR_RETURN if(!psuccess) return
And the program above becomes (AFTER):
#include<iostream.h>
int fun1(int par1, bool& psuccess)
{
if(par1 == 42) return 43;
psuccess = false;
return -1;
}
int funtoo(int a, bool& psuccess)
{
int t = fun1(a, psuccess);
SUCCES_OR_RETURN -1;
return 42;
}
void funthree(int b, bool& psuccess)
{
int h = funtoo(b, psuccess);
SUCCES_OR_RETURN ;
std::cout << "Yuppi" << b;
}
int main()
{
bool success = true;
funthree(43, success);
if(!success)
{
cout<< "Life, universe and everything have no meaning";
}
}
The question: I am wondering if there is a nicer way to handle this kind of error tracking or I have to live with this. I personally don't like the abuse of the C macro SUCCES_OR_RETURN ie. that once it is called with a parameter, and in other cases it is called without, feels like a real return statement, but I did not find any better solutions to this ancient design.
Please note that due to platform restrictions we have several restrictions, but regardless of it I am willing to hear opinions about these two:
throwing exceptions. The code is a mixture of C and C++ functions calling each other and the compiler sort of does not support throw (accepts in the syntax but does nothing with it, just a warning). This solution is sort of the standard way of solving this problem in a C++ environment.
C++11 features, this goes to a tiny embedded platform with an obscure and ancient "almost" C++ compiler which wasn't made to support the latest C++ features. However for future reference I am curios if there is anything C++11 offers.
template magic. The compiler has problems understanding complex templated issues, but again I am willing to see any solutions that you can come up with.
Edit
Also, as #BlueMoon suggested in the commend, creating a global variable is not working since at a very beginning of the function chain calling the success variable is a member variable of a class, and there are several objects of this class created, each of them needs to report its success status :)
There's a great breakdown of hybrid C and C++ error handling strategies here:
http://blog.sduto.it/2014/05/a-c-error-handling-style-that-plays.html
To quote the linked article, your options largely boil down to:
Return an error code from functions that can fail.
Provide a function like Windows's GetLastError() or OpenGL's glGetError() to retrieve the most recently occurring error code.
Provide a global (well, hopefully, thread-local) variable containing the most recent error, like POSIX's errno.
Provide a function to return more information about an error, possibly in conjunction with one of the above approaches, like POSIX's strerror function.
Allow the client to register a callback when an error occurs, like GLFW's glfwSetErrorCallback.
Use an OS-specific mechanism like structured exception handling.
Write errors out to a log file, stderr, or somewhere else.
Just assert() or somehow else terminate the program when an error occurs.
It seems like the author of the code you have inherited picked a rather strange way, passing a pointer to a boolean [sic] for the function to work with seems rather unusual.
The article has some great examples, personally I like this style:
libfoo_widget_container_t container = NULL;
libfoo_error_details_t error = NULL;
if (libfoo_create_widgets(12, &container, &error) != libfoo_success) {
printf("Error creating widgets: %s\n", libfoo_error_details_c_str(error));
libfoo_error_details_free(error);
abort(); // goodbye, cruel world!
}
Here you get a bit of everything, passed in pointer to error type, a comparison against a success constant (rather than 0|1, a painful dichotomy between C and the rest of the world!).
I don't think it would be too much of a push to say that your macro could rather better be implemented with a goto, in any case, if a function is calling SUCCES_OR_RETURN more than once, it might be a clue that the function is doing too much. Complex cleanup, or return might be a code smell, you can read more here http://eli.thegreenplace.net/2009/04/27/using-goto-for-error-handling-in-c/
I have seen this style of error handling before. I call it error-oblivious manual pseudo-exceptions.
The code flow is mostly error-oblivious: you can call 3 functions in a row with the same error flag, then look at the error flag to see if any errors have occurred.
The error flag acts as a pseudo-exception, where once set we start "skipping" over normal code flow, but this is done manually instead of automatically.
If you do something and do not care if an error occurs, you can just drop the error produced and proceed on.
The ICU library handles errors in a similar way.
A more C++1y way to do this while minimizing structural differences would be to modify code to return an expected object.
An expected<T, Err> is expected to be a T, and if something went wrong it is instead an Err type. This can be implemented as a hybrid of boost::variant and C++1y's std::optional. If you go and overload most arithmetic operations on expected< T, Err > + U to return expected< decltype( std::declval<T&>() + std::declval<U>(), Err > and did some careful auto, you could allow at least arithmetic expressions to keep their structure. You'd then check for the error after the fact.
On the other hand, if the error return values are predictable based on their type, you could create a type that when cast to a given type produced an error value. Modify functions returning void to return an error object of some kind while you are at it. And now every function can
if (berror) return error_flag_value{};
which at least gets rid of that strange ; or -1; issue.
If you want to go full C++, the answer would be changing the "invalid return values" for exceptions...
#include <iostream>
#include <exception>
using std::exception;
struct error : exception { const char* what() const throw() override { return "unsuccessful"; } };
int fun1(int par1) {
if( par1 == 42 ) return 43;
throw error();
}
int funtoo(int a) {
fun1(a);
return 42;
}
void funthree(int b) {
funtoo(b);
std::cout << "Yuppi " << b << "\n";
}
int main() {
try {
funthree(42);
} catch(exception& e) {
std::cout << "Life has no meaning, because " << e.what() << "\n";
}
}
This prints Yuppi 42 (if you change the call funthree(42) for funthree(43) it prints Life has no meaning, because unsuccessful...)
(live at coliru)
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?
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() );
}
Is there a way to stop a C++ class if there is an error in the instantiation? Like, return NULL maybe? Basically I have a wrapper class for MySQL, and the constructor does the connecting, but if the connection fails, I want the object to be, um, useless?
PDB::PDB(string _DB_IP, string _DB_USER, string _DB_PASS, string _DB_DB)
: _DB_IP( _DB_IP ), _DB_USER( _DB_USER ), _DB_PASS( _DB_PASS ), _DB_DB( _DB_DB )
{
mysql_init(&this->mysql);
this->connection = mysql_real_connect(&this->mysql, this->_DB_IP.c_str(), this->_DB_USER.c_str(), this->_DB_PASS.c_str(), this->_DB_DB.c_str(), 0, 0, 0);
if( this->connection == NULL ) // WHAT SHOULD I DO HERE, OTHER THAN THROW AN ERROR?
{
cout << mysql_error(&this->mysql) << endl;
}
this->result = NULL;
}
What should I do in the NULL test, to stop creation, etc?
Throwing an exception is really the only way to indicate an error during construction.
http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.8
If the connection can normally fail, set a flag in the object and provide an is_connected() member function for the class, and use it in your application code. If it normally cannot fail, throw an exception. The former is the pattern that the C++ Standard Library uses for opening file streams.
I have a Visual Studio 2008 C++ project that uses a Win32Exception class in cases where there is an exceptional error. The Win32Exception class looks like this:
/// defines an exception based on Win32 error codes. The what() function will
/// return a formatted string returned from FormatMessage()
class Win32Exception : public std::runtime_error
{
public:
Win32Exception() : std::runtime_error( ErrorMessage( &error_code_ ) )
{
};
virtual ~Win32Exception() { };
/// return the actual error code
DWORD ErrorCode() const throw() { return error_code_; };
private:
static std::string ErrorMessage( DWORD* error_code )
{
*error_code = ::GetLastError();
std::string error_messageA;
wchar_t* error_messageW = NULL;
DWORD len = ::FormatMessageW( FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
*error_code,
MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
reinterpret_cast< LPWSTR >( &error_messageW ),
0,
NULL );
if( NULL != error_messageW )
{
// this may generate a C4244 warning. It is safe to ignore.
std::copy( error_messageW,
error_messageW + len,
std::back_inserter( error_messageA ) );
::LocalFree( error_messageW );
}
return error_messageA;
};
/// error code returned by GetLastError()
DWORD error_code_;
}; // class Win32Exception
The class works well in the situations it has been used in. What I would like to know is if there are any obvious cases where this will fail that I should be aware of. Any other gotchas, caveats, or general suggestions on improvements are welcome.
Please note that the boost library is not an option for this code.
This has already done by several people, including yours truly
https://github.com/BillyONeal/Instalog/blob/master/LogCommon/Win32Exception.hpp
https://github.com/BillyONeal/Instalog/blob/master/LogCommon/Win32Exception.cpp
Ironically, your code is not exception safe.
if( NULL != error_messageW )
{
// this may generate a C4244 warning. It is safe to ignore.
std::copy( error_messageW,
error_messageW + len,
std::back_inserter( error_messageA ) );
::LocalFree( error_messageW );
}
Note that if the back_inserter causes std::bad_alloc to be thrown, the memory allocated inside FormatMessage is leaked.
What a coincidence! I use a similar code in all my projects! It is actually a good idea.
This code is problematic:
// this may generate a C4244 warning. It is safe to ignore.
std::copy( error_messageW,
error_messageW + len,
std::back_inserter( error_messageA ) );
It just trancates WCHARs to chars. Your can either use FormatMessageA explicitly to get a message in the current code-page (ok, you can't as you said), or make convention that all your stings are UTF-8 encoded. I chose the later, see this why.
Error message by itself may be not useful. Capturing the stack trace may be a good idea.
Realize this is old, but at least with VC++ 2015 you can throw a system_error that will do all this with the system_category() function:
try
{
throw system_error(E_ACCESSDENIED, system_category(), "Failed to write file");
}
catch (exception& ex)
{
cout << ex.what();
}
This would print: "Failed to write file: Access is denied"
FormatMessage may itself fail. Some neutral "Unknown error with code %d" might be in order for such case.
Some error codes are not really errors (ERROR_ALREADY_EXISTS), depending on what user is expecting.
Some system functions return their own error codes (notable example being SHFileOperation) that you must handle separately. If you want them to be handled, that is.
Consider having additional information inside exception: where is exception being thrown from (source file and line), what system function caused exception, what were the parameters of the function (at least the identifying ones, like file name, handle value, or some such). Stack trace is also good.
What I would like to know is if there
are any obvious cases where this will
fail that I should be aware of. Any
other gotchas, caveats, or general
suggestions on improvements are
welcome.
The main I've problem I've had with such message retrieval has been ERROR_SUCCESS. It's rather perplexing when some operation fails, accompanied by error message "The operation succeeded". One wouldn't think that could happen, but it does.
I guess this is a special case of what Dialecticus noted, that "Some error codes are not really errors", but for most of those codes at least the message is generally acceptable.
The second problem is that most Windows system error message have a carriage return + linefeed at the end. It's problematic for insertion of messages into other text, and it breaks the convention for C++ exception messages. So, good idea to remove those chars.
Now, instead of repeating all that others have already noted, a few words about the design.
The ErrorMessage function would much more usable if was made public or moved out of the class, and took the error code by value, instead of taking pointer argument. This is the principle of keeping separate responsibilities separate. Promotes reuse.
The code in ErrorMessage would be more clear and safe and efficient if you used a destructor to deallocate the memory. Then you could also just construct the string directly in the return statement instead of using a copy loop with back inserter.
Cheers & hth.,
I was recently working on a very similar class and after reading this thread tried to make the copying part exception-safe. I introduced a little helper class that does nothing but hold the pointer to the string returned by ::FormatMessage and free it with ::LocalFree in its destructor. Copying, assigning and moving is not allowed, so one cannot get into trouble.
Here is what I came up with in total:
class windows_error {
public:
windows_error(wchar_t const* what);
// Getter functions
unsigned long errorCode() const { return _code; }
wchar_t const* description() const { return _what; }
std::wstring errorMessage() const { return _sys_err_msg; }
private:
unsigned long _code;
wchar_t const* _what;
std::wstring _sys_err_msg;
};
// This class outsources the problem of managing the string which
// was allocated with ::LocalAlloc by the ::FormatMessage function.
// This is necessary to make the constructor of windows_error exception-safe.
class LocalAllocHelper {
public:
LocalAllocHelper(wchar_t* string) : _string(string) { }
~LocalAllocHelper() {
::LocalFree(_string);
}
LocalAllocHelper(LocalAllocHelper const& other) = delete;
LocalAllocHelper(LocalAllocHelper && other) = delete;
LocalAllocHelper& operator=(LocalAllocHelper const& other) = delete;
LocalAllocHelper& operator=(LocalAllocHelper && other) = delete;
private:
wchar_t* _string;
};
windows_error::windows_error(wchar_t const* what)
: _code(::GetLastError()),
_what(what) {
// Create a temporary pointer to a wide string for the error message
LPWSTR _temp_msg = 0;
// Retrieve error message from error code and save the length
// of the buffer which is being returned. This is needed to
// implement the copy and assignment constructor.
DWORD _buffer_size = ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, _code, 0, _temp_msg, 0, NULL);
if(_buffer_size) {
// When calling _sys_err_msg.resize an exception could be thrown therefore
// the _temp_msg needs to be a managed resource.
LocalAllocHelper helper(_temp_msg);
_sys_err_msg.resize(_buffer_size + 1);
std::copy(_temp_msg, _temp_msg + _buffer_size, _sys_err_msg.begin());
}
else {
_sys_err_msg = std::wstring(L"Unknown error. (FormatMessage failed)");
}
}
Maybe this will be useful for some of you.
What is a good way to return success or one or more error codes from a C++ function?
I have this member function called save(), which saves to each of the member variables, there are at least ten of these member variables that are saved-to, for the call to save(), I want to find out if the call failed, and if so, on which member variable (some are hard failures, some are soft).
You can either return an object that has multiple error fields or you can use 'out'parameters.
How you do this depends on your design and what exactly you are trying to return back. A common scenario is when you need to report back a status code along with a message of sorts. This is sometimes done where the function returns the status code as the return value and then returns the message status via an 'out' parameter.
If you are simply returning a set of 'codes', it might make more sense to construct a struct type and return that. In that case, I would be prone to pass it in as an out parameter and have the method internally update it instead of allocating a new one each time.
Are you planning on doing this once or many times?
I know this doesn't really answer your question, but...
In C++ you should use exceptions instead of returning error codes. Error codes are most commonly used by libraries which don't want to force the library user to use a particular error handling convention, but in C++, we already have stdexcept. Of course, there might be reasons you don't use exceptions, such as if you're writing embedded code or kernel extensions.
I usually use a boost::tuple:
typedef boost::tuple<int,int> return_value;
return_value r = my_function();
int first_value = boost::get<0>( r );
int second_valud = boost::get<1>( r );
EDIT
You can also use boost::tie to extract the values from a tuple:
boost::tie( first_value, second_value ) = r;
The simplest way to return two values is with the std::pair<> template:
I would use a bitset if you're intention is to purely return error states. e.g.
const bitset<10> a_not_set(1);
const bitset<10> b_not_set(2);
const bitset<10> c_not_set(4);
...
bitset<10> foo(T& a, T& b, T& c, ...)
{
bitset<10> error_code = 0;
...
if ( /* a can't be set */ )
{
error_code |= a_not_set;
}
...
if ( /* b can't be set */ )
{
error_code |= b_not_set;
}
...
// etc etc
return error_code;
}
bitset<10> err = foo(a, b, c, ... );
if (err && a_not_set)
{
// Blah.
}
You need to return them as output parameters:
bool function(int& error1, int& error2, stringx& errorText, int& error3);
You can use an integer with bit manipulation (aka flags).
I probably try to throw an exception first but it depends on your coding paradigm. Please check some books or articles about reasons why c++ exception handling might be better.
If I really need to stick to retrun-error-code style, I would define a eunm type for specifying errors with bit operations..
enum error
{
NO_ERROR = 0,
MEMBER_0_NOT_SAVED = 1,
MEMBER_1_NOT_SAVED = 1 << 1,
MEMBER_2_NOT_SAVED = 1 << 2,
// etc..
};
int save()
{
int ret = NO_ERROR;
// fail to save member_0
ret |= MEMBER_0_NOT_SAVED;
// fail to save member_1
ret |= MEMBER_1_NOT_SAVED;
// ....
return ret;
}
int main(void)
{
int ret = save();
if( ret == NO_ERROR)
{
// good.
}
else
{
if(ret & MEMBER_0_NOT_SAVED)
{
// do something
}
if(ret & MEMBER_1_NOT_SAVED)
{
// do something
}
// check the other errors...
}
}
This is just a rough example. It's better to put this into a class or use a namespace.
I am not familiar with the internals and constrains of your project, but if possible, try to use exceptions instead of error codes.
The reasons are listed here, at C++ FAQ lite, and they conclude with:
So compared to error reporting via return-codes and if, using try / catch / throw is likely to result in code that has fewer bugs, is less expensive to develop, and has faster time-to-market.