Fog Creek Software
Discussion Board




Error handling for C libraries?

How do you handle errors in your C modules?

Is it ever acceptable for a general-purpose (read: has to work in both GUI and non-GUI, threaded and non-threaded environments) C library to just print errors to stderr and exit? Is it only acceptable for catastrophic errors, like if there's no more memory available or if it can't load some type of DLL at startup?

I was thinking of adding an "error_handler" member to a library of mine's main struct that would store a function pointer that I could call like this:

RSSautomater->error_handler("This happened: %s", RSSErrorCode);

which would call a routine that intern would call vfprintf and exit. But the user could overide this behavior by setting the pointer in ->error_handler to point to their own callback function that could do what ever they wanted (log the message and keep going, log the message and exit, etc).

What are your thoughts on this? What do you typically do with your libraries? Can you point to any examples of C libraries you feel get error handling *really* right?

J. Merkalson
Sunday, March 07, 2004

I return error codes. Plain and simple. This works for all programming languages my DLLs with C interfaces are used from. Printing text anywhere from a library strikes me as extraordinarily bad design, but that may just be me..

sid6581
Sunday, March 07, 2004

Return an int error code, definitely.  0 for no error.  Assuming a Win32 library, return existing win32 error codes so that a caller can translate them into the native language with little effort.

dir at badblue dot com
Sunday, March 07, 2004

I like to use "success or fail" schemes and have
a user-registered callback to indicate that failure has
occured for some reason.  Depending on how the error
handler is set up, either the bottom-most failure
is reported or all functions report failure as they unwind.
At _that_ level, an error status and/or error message will
be reported.

Personally, I dislike error code returns unless the function is
relatively simple.

Generally, an API function should almost never "just die"
using exit() - if it's doing this, it should be for an excellent
reason (ie, the device will be damaged if we proceed,
etc...)

x
Monday, March 08, 2004

An important question here is: does your code need to support multi-threading?

If all you do is return an error code, than this isn't a problem. If OTOH you also want to return an error description, then it may be. This is because your library won't be able to use static buffers if you want MT. You can obviously pass a buffer to each function call, but that can become a hassle.

My only problem with returning 0 as a success indicator is that it results in 'reverse' if statements, sort of like strcmp. You could use 1 for success and 0 for failure with an errno-style variable (of a function if you want MT).

Dan Shappir
Monday, March 08, 2004

There is something called "Thread Local Storage" in Windows and "Thread Specific Storage" in POSIX that solves the kind of problems Dan mentions.

Hint: 'errno', despite being global, works fine with multiple threads.

Ori Berger
Monday, March 08, 2004

I like messages, and therefore the function pointer idea. For example if I need to initialize a complicated and imperfectly-documented structure and then pass it in to you as a parameter, it would be uninformative to get a E_INVALID_PARAMETER return code.

> This is because your library won't be able to use static buffers if you want MT. You can obviously pass a buffer to each function call, but that can become a hassle.

I don't see the problem. Assume the API to install a callback function like this ...

typedef void (*PFN_logmessage)(char*);
void install_logmessage_handler(PFN_logmessage);

... then the library code can use the function pointer like this ...

if (s.foo > 100))
{
  char buffer[50];
  sprintf(buffer,"Invalid 'foo' field value '%i'",s.foo);
  (*pfn_logmessage)(buffer);
}

... then it's up to the callback function to be threadsafe if the application is multi-threaded, and up to the callback function to copy the message into another buffer if it wants to buffer the message.

> RSSautomater->error_handler("This happened: %s", RSSErrorCode);

If you do that, do you need to document the maximum length of the formatted string that you will pass, so that a user-implemenation of this function knows how large a buffer it must supply in which to format the message?

In a multi-threaded environment it may also be useful to document whether you're calling the callback from your own thread, or from the user thread that caused the error.

> Is it ever acceptable for a general-purpose (read: has to work in both GUI and non-GUI, threaded and non-threaded environments) C library to just print errors to stderr and exit?

I doubt it: from a GUI program, stderr output may go nowhere, or go to a console window that disappears when the program exits; and, "general-purpose" programs include some programs that are supposed to be reliable and not exit unexpectedly.

Christopher Wells
Tuesday, March 09, 2004

*  Recent Topics

*  Fog Creek Home