nrf51 timer driver code bugs - c

I'm currently trying to make an application using the nrf51 development kit & I'm trying to use the timer driver, when I induled the C & H files of the driver I got some error :
static const nrf_drv_timer_config_t m_default_config[] = {// here it told me there is error #1
#if (TIMER0_ENABLED == 1)
NRF_DRV_TIMER_DEFAULT_CONFIG(0),
#endif
#if (TIMER1_ENABLED == 1)
NRF_DRV_TIMER_DEFAULT_CONFIG(1),
#endif
#if (TIMER2_ENABLED == 1)
NRF_DRV_TIMER_DEFAULT_CONFIG(2)
#endif
};
// here it told me there is error #2
ret_code_t nrf_drv_timer_init(nrf_drv_timer_t const * const p_instance,
nrf_drv_timer_config_t const * p_config,
nrf_timer_event_handler_t timer_event_handler)
{
ASSERT((p_instance->instance_id) < TIMER_INSTANCE_NUMBER);
ASSERT(TIMER_IS_BIT_WIDTH_VALID(p_instance->instance_id, p_config->bit_width));
if (m_cb[p_instance->instance_id].state != NRF_DRV_STATE_UNINITIALIZED)
{
return NRF_ERROR_INVALID_STATE; // timer already initialized
}
if (p_config == NULL)
{
p_config = &m_default_config[p_instance->instance_id];
}
#ifdef SOFTDEVICE_PRESENT
if (p_instance->p_reg == NRF_TIMER0)
{
return NRF_ERROR_INVALID_PARAM;
}
#endif
nrf_drv_common_irq_enable(p_instance->irq, p_config->interrupt_priority);
mp_contexts[p_instance->instance_id] = p_config->p_context;
if (timer_event_handler != NULL)
{
m_timer_event_handlers[p_instance->instance_id] = timer_event_handler;
}
else
{
return NRF_ERROR_INVALID_PARAM;
}
nrf_timer_mode_set(p_instance->p_reg, p_config->mode);
nrf_timer_bit_width_set(p_instance->p_reg, p_config->bit_width);
nrf_timer_frequency_set(p_instance->p_reg, p_config->frequency);
m_cb[p_instance->instance_id].state = NRF_DRV_STATE_INITIALIZED;
return NRF_SUCCESS;
}
the error #1 says that "an empty initializer is invalid for an array with unspecified bound"
the error #2 says that it expected an expression
I till now didn't use any of these functions in the main.c code, I'm just added the header files that will be used further.

Error 1: Apparently neither of TIMERx_ENABLED is 1, so the array will be empty. As it is const, there is no chance to initialize it later. That would also result in an array of zero elements, which is not allowed. Easiest might be to have an #else clause with a single null entry. However, I suspect you have to configure the stuff for your system first. Read the documentation.
Error 2: might be a follow up error, or one of the custom types are not defined - hard to say without more info, or the location the error is reported is simply not that of the actual error, or ... . Best is to fix the first error, then try again for error 2.

If you are using examples from nordic then the defines are either in nrf_drv_config.h or in the sdk_config.h for new versions of the nordic sdk.
You have to enable the timers by changing the TIMER_ENABLED define to 1. Then do the same for the timers you want to use.
You could make these defines yourself as other people have suggested.

Related

Extent of MISRA C 2012 Directive 4.1: Runtime checks before pointer dereferencing in a library

MISRA C 2012 Directive 4.1 says that Run-time failures should be minimized and further states for pointer dereferencing that a pointer should be checked for NULL before it's dereferenced,
unless it's already known to be not NULL.
When writing a library performing simple operations, checking the input pointers in each library function
for NULL creates larger and therefore less understandable code even for simple operations.
For example below library computes the squared euclidian norm of a vector and gets used in a controller
/*** Option 1: Checking pointers ***/
Library:
/* file vector.c */
bool_t bVectorNormSq(float32_t pf32Vec[], uint8_t u8Len, float32_t *pf32NormSq)
{
uint8_t u8n;
bool bRet = false;
/* Check pointers */
if( (pf32Vec != NULL) && (pf32NormSq != NULL) )
{
*pf32NormSq = 0.0f;
for(u8n = 0U; u8n < u8Len; u8n++)
{
*pf32NormSq += (pf32Vec[u8n] * pf32Vec[u8n]);
}
bRet = true;
}
else
{
/* Do not alter pf32NormSq (unknown if valid pointer) */
bRet = false;
}
return bRet;
}
/* EOF */
Consumer of library:
/* file controller.c */
/* ... */
bool_t bControllerStep(void)
{
float32_t pf32MyVec[3] = { 0 };
float32_t f32MyNorm = 0.0f;
/* ... */
/* MISRA C 2012 Rule 17.7, Call will always be successful, thus return value not checked */
(void)bVectorNormSq(pf32MyVec, 3U, &f32MyNorm);
/* ... */
}
/* EOF */
/*** Option 2: Not checking pointer, responsibility to supply valid inputs placed on caller ***/
Library:
/* file vector.c */
/**
* #note This library assumes that valid pointers will be supplied,
* pointers are NOT checked before they are used.
*/
/* Assert macro expands to "(void)(CONDITION)" for NDEBUG defined */
#ifdef NDEBUG
VECTOR_ASSERT( CONDITION ) (void)(CONDITION)
#else
/* ... */
#endif /* NDEBUG */
float32_t f32VectorNormSq(float32_t pf32Vec[], uint8_t u8Len)
{
float32_t f32Norm = 0.0f;
uint8_t u8n = 0U;
VECTOR_ASSERT(pf32Vec!=NULL);
for(u8n = 0U; u8n < u8Len; u8n++)
{
f32NormSq += (pf32Vec[u8n] * pf32Vec[u8n]);
}
}
/* EOF */
Consumer of library:
/* file controller.c */
/* ... */
bool_t bControllerStep(void)
{
float32_t pf32MyVec[3] = { 0 };
float32_t f32MyNorm = 0.0f;
/* ... */
f32MyNorm = f32VectorNormSq(pf32MyVec, 3U);
/* ... */
}
/* EOF */
For option 1 the library function f32VectorNormSq() can be reasoned by the caller bControllerStep() to always execute successfully (return true),
because the array pf32MyVec is defined in the caller and pf32MyVec thus can't be NULL. Therefore the caller chooses to ignore the return value.
Above reasoning is likely to be the applicable for many uses of the library, resulting in callers
frequently ignoring return values for option 1. This could lead to a programmer being complacend in ignoring return values, even if they shouldn't, e.g. because a
zero division was detected by the library.
Opposed to this option 2 assumes the caller supplying valid pointers, documents this in the library /* #note...*/ and only uses a assert for NULL pointers to assist during development,
later to be disabled for deployment. In this option a Boolean return value being present highlights to the programmer that the library operation might fail for reasons
other than invalid pointers or incorrect other trivial inputs, e.g due to zero division and care should be taken before using the computed values,
avoiding the risk of complacency.
Therefore my question(s):
Is it situations as in the example shown compliant to MISRA C for a libary to neglect checking pointers or other trivial inputs?
Are there any additional conditions that have to be fullfilled, besides documenting the missing input checking in the source code, e.g. is a formal deviation needed?
Application background:
This is just an aerospace student with focus in control systems, trying to understand how things are done properly in the actual coding of control systems, by writing his own control algorithms as if they were running on the real thing i.e. by following standards like MISRA C.
Code written by me will NOT be going on a live system anytime soon, but for the purpose of your answers please consider this code as running on the actual system where a failure of the function is classified as catastrophic, .i.e. everybody dies.
I'm aware of the whole software and hardware engineering (SAE ARP4754, SAE ARP4761, DO-178C, ...) around the actual implementation process. This question is really just about the instructions executing on the hardware, not about the need for redudant & dissimilar hardware or requirements, reviews, testing, ...
EDIT:
The library in question is low in the code stack thus sanitizing code for inputs from the outside (sensors,...) can be expected to be present. I'm trying to avoid falling prey to Cargo cult programming by blindly following the rule "Always check all inputs".
Regarding Option 1 - how would you write the documentation to that function? Does this make sense:
bVectorNormSq
Description of what this function does here.
pf32Vec A pointer to an allocated array of [u8Len] that will-...
u8Len The size of the array [pf32Vec] in bytes.
...
Returns: true if successful, false in case pf32Vec was a null pointer.
It doesn't make sense. You already documented that pf32Vec must be a pointer to an allocated array so why would the usernot read that part, but read the part about return status? How are we even supposed to use this function?
bool result = bVectorNormSq(some_fishy_pointer, ...); // checks for null internally
if(result == false)
{
/* error: you passed a null pointer */
}
Why can't you instead write that very same code like this?
if(some_fishy_pointer == NULL)
{
/* handle the error instead of calling the function in the first place */
}
else
{
bVectorNormSq(some_fishy_pointer, ...); // does not check for null internally
}
It's the same amount of error checking, same amount of branches. Literally the only difference is the slower execution speed of the first version.
Also, your extra error checks add extra complexity which could in turn lead to extra bugs.
Potential bugs:
if( (pf32Vec = NULL) ||(pf32NormSq = NULL) )
or
if( (pf32Vec =! NULL) && (pf32NormSq != NULL) )
or (not just a potential bug):
bool_t ... bool bRet = false; ... return bRet;
Extra error checking is a good thing, but place it where it matters - sanitize data at the point where it gets assigned. Example:
const char* ptr = strstr(x,y);
if(ptr == NULL) // Correct! Check close to the location where the pointer is set
{}
...
some_function(ptr);
...
void some_function (const char* str)
{
if(str == NULL) // Not correct. This function has nothing to do with the strstr call.
}

In C, what is the best practice for handling errors in your own functions? [duplicate]

What do you consider "best practice" when it comes to error handling errors in a consistent way in a C library.
There are two ways I've been thinking of:
Always return error code. A typical function would look like this:
MYAPI_ERROR getObjectSize(MYAPIHandle h, int* returnedSize);
The always provide an error pointer approach:
int getObjectSize(MYAPIHandle h, MYAPI_ERROR* returnedError);
When using the first approach it's possible to write code like this where the error handling check is directly placed on the function call:
int size;
if(getObjectSize(h, &size) != MYAPI_SUCCESS) {
// Error handling
}
Which looks better than the error handling code here.
MYAPIError error;
int size;
size = getObjectSize(h, &error);
if(error != MYAPI_SUCCESS) {
// Error handling
}
However, I think using the return value for returning data makes the code more readable, It's obvious that something was written to the size variable in the second example.
Do you have any ideas on why I should prefer any of those approaches or perhaps mix them or use something else? I'm not a fan of global error states since it tends to make multi threaded use of the library way more painful.
EDIT:
C++ specific ideas on this would also be interesting to hear about as long as they are not involving exceptions since it's not an option for me at the moment...
I've used both approaches, and they both worked fine for me. Whichever one I use, I always try to apply this principle:
If the only possible errors are programmer errors, don't return an error code, use asserts inside the function.
An assertion that validates the inputs clearly communicates what the function expects, while too much error checking can obscure the program logic. Deciding what to do for all the various error cases can really complicate the design. Why figure out how functionX should handle a null pointer if you can instead insist that the programmer never pass one?
I like the error as return-value way. If you're designing the api and you want to make use of your library as painless as possible think about these additions:
store all possible error-states in one typedef'ed enum and use it in your lib. Don't just return ints or even worse, mix ints or different enumerations with return-codes.
provide a function that converts errors into something human readable. Can be simple. Just error-enum in, const char* out.
I know this idea makes multithreaded use a bit difficult, but it would be nice if application programmer can set an global error-callback. That way they will be able to put a breakpoint into the callback during bug-hunt sessions.
There's a nice set of slides from CMU's CERT with recommendations for when to use each of the common C (and C++) error handling techniques. One of the best slides is this decision tree:
I would personally change two things about this flowcart.
First, I would clarify that sometimes objects should use return values to indicate errors. If a function only extracts data from an object but doesn't mutate the object, then the integrity of the object itself is not at risk and indicating errors using a return value is more appropriate.
Second, it's not always appropriate to use exceptions in C++. Exceptions are good because they can reduce the amount of source code devoted to error handling, they mostly don't affect function signatures, and they're very flexible in what data they can pass up the callstack. On the other hand, exceptions might not be the right choice for a few reasons:
C++ exceptions have very particular semantics. If you don't want those semantics, then C++ exceptions are a bad choice. An exception must be dealt with immediately after being thrown and the design favors the case where an error will need to unwind the callstack a few levels.
C++ functions that throw exceptions can't later be wrapped to not throw exceptions, at least not without paying the full cost of exceptions anyway. Functions that return error codes can be wrapped to throw C++ exceptions, making them more flexible. C++'s new gets this right by providing a non-throwing variant.
C++ exceptions are relatively expensive but this downside is mostly overblown for programs making sensible use of exceptions. A program simply shouldn't throw exceptions on a codepath where performance is a concern. It doesn't really matter how fast your program can report an error and exit.
Sometimes C++ exceptions are not available. Either they're literally not available in one's C++ implementation, or one's code guidelines ban them.
Since the original question was about a multithreaded context, I think the local error indicator technique (what's described in SirDarius's answer) was underappreciated in the original answers. It's threadsafe, doesn't force the error to be immediately dealt with by the caller, and can bundle arbitrary data describing the error. The downside is that it must be held by an object (or I suppose somehow associated externally) and is arguably easier to ignore than a return code.
I use the first approach whenever I create a library. There are several advantages of using a typedef'ed enum as a return code.
If the function returns a more complicated output such as an array and its length you do not need to create arbitrary structures to return.
rc = func(..., int **return_array, size_t *array_length);
It allows for simple, standardized error handling.
if ((rc = func(...)) != API_SUCCESS) {
/* Error Handling */
}
It allows for simple error handling in the library function.
/* Check for valid arguments */
if (NULL == return_array || NULL == array_length)
return API_INVALID_ARGS;
Using a typedef'ed enum also allows for the enum name to be visible in the debugger. This allows for easier debugging without the need to constantly consult a header file. Having a function to translate this enum into a string is helpful as well.
The most important issue regardless of approach used is to be consistent. This applies to function and argument naming, argument ordering and error handling.
Returning error code is the usual approach for error handling in C.
But recently we experimented with the outgoing error pointer approach as well.
It has some advantages over the return value approach:
You can use the return value for more meaningful purposes.
Having to write out that error parameter reminds you to handle the error or propagate it. (You never forget checking the return value of fclose, don't you?)
If you use an error pointer, you can pass it down as you call functions. If any of the functions set it, the value won't get lost.
By setting a data breakpoint on the error variable, you can catch where does the error occurred first. By setting a conditional breakpoint you can catch specific errors too.
It makes it easier to automatize the check whether you handle all errors. The code convention may force you to call your error pointer as err and it must be the last argument. So the script can match the string err); then check if it's followed by if (*err. Actually in practice we made a macro called CER (check err return) and CEG (check err goto). So you don't need to type it out always when we just want to return on error, and can reduce the visual clutter.
Not all functions in our code has this outgoing parameter though.
This outgoing parameter thing are used for cases where you would normally throw an exception.
Here's a simple program to demonstrate the first 2 bullets of Nils Pipenbrinck's answer here.
His first 2 bullets are:
store all possible error-states in one typedef'ed enum and use it in your lib. Don't just return ints or even worse, mix ints or different enumerations with return-codes.
provide a function that converts errors into something human readable. Can be simple. Just error-enum in, const char* out.
Assume you have written a module named mymodule. First, in mymodule.h, you define your enum-based error codes, and you write some error strings which correspond to these codes. Here I am using an array of C strings (char *), which only works well if your first enum-based error code has value 0, and you don't manipulate the numbers thereafter. If you do use error code numbers with gaps or other starting values, you'll simply have to change from using a mapped C-string array (as I do below) to using a function which uses a switch statement or if / else if statements to map from enum error codes to printable C strings (which I don't demonstrate). The choice is yours.
mymodule.h
/// #brief Error codes for library "mymodule"
typedef enum mymodule_error_e
{
/// No error
MYMODULE_ERROR_OK = 0,
/// Invalid arguments (ex: NULL pointer where a valid pointer is required)
MYMODULE_ERROR_INVARG,
/// Out of memory (RAM)
MYMODULE_ERROR_NOMEM,
/// Make up your error codes as you see fit
MYMODULE_ERROR_MYERROR,
// etc etc
/// Total # of errors in this list (NOT AN ACTUAL ERROR CODE);
/// NOTE: that for this to work, it assumes your first error code is value 0 and you let it naturally
/// increment from there, as is done above, without explicitly altering any error values above
MYMODULE_ERROR_COUNT,
} mymodule_error_t;
// Array of strings to map enum error types to printable strings
// - see important NOTE above!
const char* const MYMODULE_ERROR_STRS[] =
{
"MYMODULE_ERROR_OK",
"MYMODULE_ERROR_INVARG",
"MYMODULE_ERROR_NOMEM",
"MYMODULE_ERROR_MYERROR",
};
// To get a printable error string
const char* mymodule_error_str(mymodule_error_t err);
// Other functions in mymodule
mymodule_error_t mymodule_func1(void);
mymodule_error_t mymodule_func2(void);
mymodule_error_t mymodule_func3(void);
mymodule.c contains my mapping function to map from enum error codes to printable C strings:
mymodule.c
#include <stdio.h>
/// #brief Function to get a printable string from an enum error type
/// #param[in] err a valid error code for this module
/// #return A printable C string corresponding to the error code input above, or NULL if an invalid error code
/// was passed in
const char* mymodule_error_str(mymodule_error_t err)
{
const char* err_str = NULL;
// Ensure error codes are within the valid array index range
if (err >= MYMODULE_ERROR_COUNT)
{
goto done;
}
err_str = MYMODULE_ERROR_STRS[err];
done:
return err_str;
}
// Let's just make some empty dummy functions to return some errors; fill these in as appropriate for your
// library module
mymodule_error_t mymodule_func1(void)
{
return MYMODULE_ERROR_OK;
}
mymodule_error_t mymodule_func2(void)
{
return MYMODULE_ERROR_INVARG;
}
mymodule_error_t mymodule_func3(void)
{
return MYMODULE_ERROR_MYERROR;
}
main.c contains a test program to demonstrate calling some functions and printing some error codes from them:
main.c
#include <stdio.h>
int main()
{
printf("Demonstration of enum-based error codes in C (or C++)\n");
printf("err code from mymodule_func1() = %s\n", mymodule_error_str(mymodule_func1()));
printf("err code from mymodule_func2() = %s\n", mymodule_error_str(mymodule_func2()));
printf("err code from mymodule_func3() = %s\n", mymodule_error_str(mymodule_func3()));
return 0;
}
Output:
Demonstration of enum-based error codes in C (or C++)
err code from mymodule_func1() = MYMODULE_ERROR_OK
err code from mymodule_func2() = MYMODULE_ERROR_INVARG
err code from mymodule_func3() = MYMODULE_ERROR_MYERROR
References:
You can run this code yourself here: https://onlinegdb.com/ByEbKLupS.
My answer I frequently reference to see this type of error handling: STM32 how to get last reset status
I personally prefer the former approach (returning an error indicator).
Where necessary the return result should just indicate that an error occurred, with another function being used to find out the exact error.
In your getSize() example I'd consider that sizes must always be zero or positive, so returning a negative result can indicate an error, much like UNIX system calls do.
I can't think of any library that I've used that goes for the latter approach with an error object passed in as a pointer. stdio, etc all go with a return value.
The UNIX approach is most similar to your second suggestion. Return either the result or a single "it went wrong" value. For instance, open will return the file descriptor on success or -1 on failure. On failure it also sets errno, an external global integer to indicate which failure occurred.
For what it's worth, Cocoa has also been adopting a similar approach. A number of methods return BOOL, and take an NSError ** parameter, so that on failure they set the error and return NO. Then the error handling looks like:
NSError *error = nil;
if ([myThing doThingError: &error] == NO)
{
// error handling
}
which is somewhere between your two options :-).
Use setjmp.
http://en.wikipedia.org/wiki/Setjmp.h
http://aszt.inf.elte.hu/~gsd/halado_cpp/ch02s03.html
http://www.di.unipi.it/~nids/docs/longjump_try_trow_catch.html
#include <setjmp.h>
#include <stdio.h>
jmp_buf x;
void f()
{
longjmp(x,5); // throw 5;
}
int main()
{
// output of this program is 5.
int i = 0;
if ( (i = setjmp(x)) == 0 )// try{
{
f();
} // } --> end of try{
else // catch(i){
{
switch( i )
{
case 1:
case 2:
default: fprintf( stdout, "error code = %d\n", i); break;
}
} // } --> end of catch(i){
return 0;
}
#include <stdio.h>
#include <setjmp.h>
#define TRY do{ jmp_buf ex_buf__; if( !setjmp(ex_buf__) ){
#define CATCH } else {
#define ETRY } }while(0)
#define THROW longjmp(ex_buf__, 1)
int
main(int argc, char** argv)
{
TRY
{
printf("In Try Statement\n");
THROW;
printf("I do not appear\n");
}
CATCH
{
printf("Got Exception!\n");
}
ETRY;
return 0;
}
When I write programs, during initialization, I usually spin off a thread for error handling, and initialize a special structure for errors, including a lock. Then, when I detect an error, through return values, I enter in the info from the exception into the structure and send a SIGIO to the exception handling thread, then see if I can't continue execution. If I can't, I send a SIGURG to the exception thread, which stops the program gracefully.
I have done a lot of C programming in the past. And I really apreciated the error code return value. But is has several possible pitfalls:
Duplicate error numbers, this can be solved with a global errors.h file.
Forgetting to check the error code, this should be solved with a cluebat and long debugging hours. But in the end you will learn (or you will know that someone else will do the debugging).
I ran into this Q&A a number of times, and wanted to contribute a more comprehensive answer. I think the best way to think about this is how to return errors to the caller, and what you return.
How
There are 3 ways to return information from a function:
Return Value
Out Argument(s)
Out of Band, that includes non-local goto (setjmp/longjmp),
file or global scoped variables, file system etc.
Return Value
You can only return a single value (object); however, it can be an arbitrarily complex value. Here is an example of an error returning function:
enum error hold_my_beer(void);
One benefit of return values is that it allows chaining of calls for less intrusive error handling:
!hold_my_beer() &&
!hold_my_cigarette() &&
!hold_my_pants() ||
abort();
This not just about readability, but may also allow processing an array of such function pointers in a uniform way.
Out Argument(s)
You can return more via more than one object via arguments, but best practice does suggest to keep the total number of arguments low (say, <=4):
void look_ma(enum error *e, char *what_broke);
enum error e;
look_ma(e);
if(e == FURNITURE) {
reorder(what_broke);
} else if(e == SELF) {
tell_doctor(what_broke);
}
This forces caller to pass in object which may make it more likely that it's being checked. If you have a set of calls all returning errors, and you decide to allocate a new variable to each, then it add some clutter in the caller.
Out of Band
The best known example is probably the (thread-local) errno variable, which the called function sets. It's very easy for the callee to not check this variable, and you only get one which may be an issue if your function is complicated (for instance, two parts of the function returning the same error code).
With setjmp() you define a place and how you want to handle an int value, and you transfer control to that location via a longjmp(). See Practical usage of setjmp and longjmp in C.
What
Indicator
Code
Object
Callback
Indicator
An error indicator only tells you that there is a problem but nothing about the nature of said problem:
struct foo *f = foo_init();
if(!f) {
/// handle the absence of foo
}
This is the least powerful way for a function to communicate error state; however, it's perfect if the caller cannot respond to the error in a graduated manner anyways.
Code
An error code tells the caller about the nature of the problem, and may allow for a suitable response (from the above). It can be a return value, or like the look_ma() example above an error argument.
Object
With an error object, the caller can be informed about arbitrarily complicated issues. For example, an error code and a suitable human-readable message. It can also inform the caller that multiple things went wrong, or an error per item when processing a collection:
struct collection friends;
enum error *e = malloc(c.size * sizeof(enum error));
...
ask_for_favor(friends, reason);
for(int i = 0; i < c.size; i++) {
if(reason[i] == NOT_FOUND) find(friends[i]);
}
Instead of pre-allocating the error array, you can also (re)allocate it dynamically as needed of course.
Callback
Callback is the most powerful way to handle errors, as you can tell the function what behavior you would like to see happen when something goes wrong. A callback argument can be added to each function, or if customization uis only required per instance of a struct like this:
struct foo {
...
void (error_handler)(char *);
};
void default_error_handler(char *message) {
assert(f);
printf("%s", message);
}
void foo_set_error_handler(struct foo *f, void (*eh)(char *)) {
assert(f);
f->error_handler = eh;
}
struct foo *foo_init() {
struct foo *f = malloc(sizeof(struct foo));
foo_set_error_handler(f, default_error_handler);
return f;
}
struct foo *f = foo_init();
foo_something();
One interesting benefit of a callback is that it can be invoked multiple times, or none at all in the absence of errors in which there is no overhead on the happy path.
There is, however, an inversion of control. The calling code does not know if the callback was invoked. As such, it may make sense to use an indicator as well.
I was pondering this issue recently as well, and wrote up some macros for C that simulate try-catch-finally semantics using purely local return values. Hope you find it useful.
Here is an approach which I think is interesting, while requiring some discipline.
This assumes a handle-type variable is the instance on which operate all API functions.
The idea is that the struct behind the handle stores the previous error as a struct with necessary data (code, message...), and the user is provided with a function that returns a pointer to this error object. Each operation will update the pointed object so the user can check its status without even calling functions. As opposed to the errno pattern, the error code is not global, which make the approach thread-safe, as long as each handle is properly used.
Example:
MyHandle * h = MyApiCreateHandle();
/* first call checks for pointer nullity, since we cannot retrieve error code
on a NULL pointer */
if (h == NULL)
return 0;
/* from here h is a valid handle */
/* get a pointer to the error struct that will be updated with each call */
MyApiError * err = MyApiGetError(h);
MyApiFileDescriptor * fd = MyApiOpenFile("/path/to/file.ext");
/* we want to know what can go wrong */
if (err->code != MyApi_ERROR_OK) {
fprintf(stderr, "(%d) %s\n", err->code, err->message);
MyApiDestroy(h);
return 0;
}
MyApiRecord record;
/* here the API could refuse to execute the operation if the previous one
yielded an error, and eventually close the file descriptor itself if
the error is not recoverable */
MyApiReadFileRecord(h, &record, sizeof(record));
/* we want to know what can go wrong, here using a macro checking for failure */
if (MyApi_FAILED(err)) {
fprintf(stderr, "(%d) %s\n", err->code, err->message);
MyApiDestroy(h);
return 0;
}
First approach is better IMHO:
It's easier to write function that way. When you notice an error in the middle of the function you just return an error value. In second approach you need to assign error value to one of the parameters and then return something.... but what would you return - you don't have correct value and you don't return error value.
it's more popular so it will be easier to understand, maintain
I definitely prefer the first solution :
int size;
if(getObjectSize(h, &size) != MYAPI_SUCCESS) {
// Error handling
}
i would slightly modify it, to:
int size;
MYAPIError rc;
rc = getObjectSize(h, &size)
if ( rc != MYAPI_SUCCESS) {
// Error handling
}
In additional i will never mix legitimate return value with error even if currently the scope of function allowing you to do so, you never know which way function implementation will go in the future.
And if we already talking about error handling i would suggest goto Error; as error handling code, unless some undo function can be called to handle error handling correctly.
What you could do instead of returning your error, and thus forbidding you from returning data with your function, is using a wrapper for your return type:
typedef struct {
enum {SUCCESS, ERROR} status;
union {
int errCode;
MyType value;
} ret;
} MyTypeWrapper;
Then, in the called function:
MyTypeWrapper MYAPIFunction(MYAPIHandle h) {
MyTypeWrapper wrapper;
// [...]
// If there is an error somewhere:
wrapper.status = ERROR;
wrapper.ret.errCode = MY_ERROR_CODE;
// Everything went well:
wrapper.status = SUCCESS;
wrapper.ret.value = myProcessedData;
return wrapper;
}
Please note that with the following method, the wrapper will have the size of MyType plus one byte (on most compilers), which is quite profitable; and you won't have to push another argument on the stack when you call your function (returnedSize or returnedError in both of the methods you presented).
In addition to what has been said, prior to returning your error code, fire off an assert or similar diagnostic when an error is returned, as it will make tracing a lot easier. The way I do this is to have a customised assert that still gets compiled in at release but only gets fired when the software is in diagnostics mode, with an option to silently report to a log file or pause on screen.
I personally return error codes as negative integers with no_error as zero , but it does leave you with the possible following bug
if (MyFunc())
DoSomething();
An alternative is have a failure always returned as zero, and use a LastError() function to provide details of the actual error.
EDIT:If you need access only to the last error, and you don't work in multithreaded environment.
You can return only true/false (or some kind of #define if you work in C and don't support bool variables), and have a global Error buffer that will hold the last error:
int getObjectSize(MYAPIHandle h, int* returnedSize);
MYAPI_ERROR LastError;
MYAPI_ERROR* getLastError() {return LastError;};
#define FUNC_SUCCESS 1
#define FUNC_FAIL 0
if(getObjectSize(h, &size) != FUNC_SUCCESS ) {
MYAPI_ERROR* error = getLastError();
// error handling
}
Second approach lets the compiler produce more optimized code, because when address of a variable is passed to a function, the compiler cannot keep its value in register(s) during subsequent calls to other functions. The completion code usually is used only once, just after the call, whereas "real" data returned from the call may be used more often
I prefer error handling in C using the following technique:
struct lnode *insert(char *data, int len, struct lnode *list) {
struct lnode *p, *q;
uint8_t good;
struct {
uint8_t alloc_node : 1;
uint8_t alloc_str : 1;
} cleanup = { 0, 0 };
// allocate node.
p = (struct lnode *)malloc(sizeof(struct lnode));
good = cleanup.alloc_node = (p != NULL);
// good? then allocate str
if (good) {
p->str = (char *)malloc(sizeof(char)*len);
good = cleanup.alloc_str = (p->str != NULL);
}
// good? copy data
if(good) {
memcpy ( p->str, data, len );
}
// still good? insert in list
if(good) {
if(NULL == list) {
p->next = NULL;
list = p;
} else {
q = list;
while(q->next != NULL && good) {
// duplicate found--not good
good = (strcmp(q->str,p->str) != 0);
q = q->next;
}
if (good) {
p->next = q->next;
q->next = p;
}
}
}
// not-good? cleanup.
if(!good) {
if(cleanup.alloc_str) free(p->str);
if(cleanup.alloc_node) free(p);
}
// good? return list or else return NULL
return (good ? list : NULL);
}
Source: http://blog.staila.com/?p=114
In addition the other great answers, I suggest that you try to separate the error flag and the error code in order to save one line on each call, i.e.:
if( !doit(a, b, c, &errcode) )
{ (* handle *)
(* thine *)
(* error *)
}
When you have lots of error-checking, this little simplification really helps.
I have seen five main approaches used in error reporting by functions in C:
return value with no error code reporting or no return value
return value that is an error code only
return value that is a valid value or an error code value
return value indicating an error with some way of fetching an error code possibly with error context information
function argument that returns a value with an error code possibly with error context information
In addition to the choice of function error return mechanism there is also the consideration of error code mnemonics and ensuring that the error code mnemonics do not clash with any other error code mnemonics being used. Typically this requires the use of a Three Letter Prefix approach to the naming of mnemonics defining them with #define, enum, or const static int. See this discussion "static const" vs "#define" vs "enum"
There are a couple of different outcomes once an error is detected and that may be a consideration how functions provide error codes and error information. These outcomes are really divided into two camps, recoverable errors and unrecoverable errors:
document the system state and then abort
wait and retry the failed action
notify a human being and request assistance
continue execution in a degraded state
An error type may use more than one of these outcomes depending on the context of the error. For instance a file open that fails because the file doesn't exist may be retried with a different file name or notify a user and ask for assistance or continue execution in a degraded state.
Details on Five Main Approaches
Some functions do not provide an error code. The functions either can't fail or if they fail, they fail silently. An example of this type of function are the various is character test functions such as isdigit() which indicates if a character value is a digit or is not. A character value either is or is not a digit or an alphabetic character. Similarly with the strcmp() function, comparing two strings results in a value indicating which one is higher in the collating sequence than the other should they not be the same.
In some cases an error code is not necessary because a value indicating failure is a valid result. For example the strchr() function from the Standard Library returns a pointer to the searched for character if found in the string to be scanned or NULL if it is not found. In this case a failure to find the character is a valid and useful indicator. A function using strchr() may require the character searched for not be in the string to be successful and finding the character is an error condition.
Other functions do not return an error code but instead report an error through an external mechanism. This is used by most of the math library functions in the Standard Library which require the user to set errno to a value of zero, call the function, and then check that the value of errno is still zero. The range of output values from many of the math functions do not allow a special return value to be used to indicate an error and they do not have an error reporting argument in their interfaces.
Some functions perform an action and return an error code value with one of the possible error code values indicating success and the rest of the range of values indicating an error code. For example a function may return a value of 0 if successful or a positive or negative non-zero value indicating an error with the value returned being the error code.
Some functions may perform an action and return either a value from a range of valid values if successful or a value from a range of invalid values indicating an error code. A simple approach is to use a positive value (0, 1, 2, ...) for valid values and a negative value for error codes allowing a check such as if(status < 0) return error;.
Some functions return a valid value or an invalid value indicating an error requiring the additional step of fetching the error code by some means. For example the fopen() function returns either a pointer to a FILE object or it returns an invalid pointer value of NULL and sets errno to an error code indicating the reason for the failure. A number of Windows API functions that return a HANDLE value to reference a resource may also return a value of INVALID_HANDLE_VALUE and the function GetLastError() is used to obtain the error code. The OPOS Control Objects standard requires an OPOS Control Object to provide two functions, GetResultCode() and GetResultCodeExtended(), to allow for the retrieval of error status information in the event a COM object method call fails.
This same approach is used in other APIs that use a handle or reference to a resource in which there is a range of valid values with one or more values outside of that range used to indicate an error. A mechanism is then provided to fetch additional error information such as an error code.
A similar approach is used with functions that return a boolean value of true to indicate the function was successful or false to indicate an error. The programmer must then examine other data to determine an error code such as GetLastError() with the Windows API.
Some functions have a pointer argument containing the address of a memory area for the function called to provide an error code or error information. Where this approach really shines is when in addition to a simple error code there is additional, error context information that helps to pin point the error. For example a JSON string parsing function may not only return an error code but also a pointer to where in the JSON string the parsing failed.
I have also seen functions where the function returned an error indicator such as a boolean value with the argument used for error information. I recall that the error information argument could in some cases be NULL indicating the caller didn't want to know the specifics of a failure.
This approach to returning error code or error information seems to be uncommon in my experience though for some reason I think I've seen it used in the Windows API from time to time or perhaps with an XML parser.
Considerations for multi-threading
When using the approach of an additional error code access through a mechanism as in checking a global such as errno or using a function such as GetLastError() there is the problem of sharing the global across multiple threads.
Modern compilers and libraries deal with this by using thread local storage to ensure that each thread has its own storage that is not shared by other threads. However there is still the issue of multiple functions sharing the same thread local storage location for status information which may require some accomodation. For instance, a function that uses several files may need to work around the issue that all of the fopen() calls that may fail share a single errno in the same thread.
If the API uses some type of handle or reference then error code storage can be made handle specific. The fopen() function could be wrapped in another function which performs the fopen() and then sets an API control block with both the FILE * returned by the fopen() as well as the value of errno.
The approach I prefer
My preference is for an error code to be returned as a function return value so that I can either check it at the point of call or save it for later. In most cases, an error is something to be dealt with immediately which is why I prefer this approach.
An approach I have used with functions is to have the function return a simple struct which contains two members, a status code and the return value. For example:
struct FuncRet {
short sStatus; // status or error code
double dValue; // calculated value
};
struct FuncRet Func(double dInput)
{
struct FuncRet = {0, 0}; // sStatus == 0 indicates success
// calculate return value FuncRet.dValue and set
// status code FuncRet.sStatus in the event of an error.
return FuncRet;
}
// ... source code before using our function.
{
struct FuncRet s;
if ((s = Func(aDble)).sStatus == 0) {
// do things with the valid value s.dValue
} else {
// error so deal with the error reported in s.sStatus
}
}
This allows me to do an immediate check for an error. Many functions end up returning a status without returning an actual value as well because the data returned is complex. One or more arguments may be modified by the function but the function doesn't return a value other than a status code.

What is "IsA()" function in C?

In pure C code in different projects that involve Postgresql server programming which I'm working with now, I keep encountering the function "IsA()" which returns a boolean and checks whether or not 2 instances of a struct belong to the same struct. I suppose.
One of them:
https://github.com/guotao0628/pipelinedb/blob/master/src/backend/executor/nodeBitmapAnd.c#L123
for (i = 0; i < nplans; i++)
{
PlanState *subnode = bitmapplans[i];
TIDBitmap *subresult;
subresult = (TIDBitmap *) MultiExecProcNode(subnode);
if (!subresult || !IsA(subresult, TIDBitmap)) /*what's IsA(...) ? */
elog(ERROR, "unrecognized result from subplan");
if (result == NULL)
result = subresult; /* first subplan */
I need to port some of that C code to other strictly typed language. Hence, I need to know how "isA()" is implemented under the hood. But I haven't found it anywhere. Supposedly it's defined in some library.
Where can I find its definition?
IsA is a macro which is defined in this header file in Postgresql source code.

determining original cause of error

Is there some well known pattern/practice for nested error handling in C, something like nested exceptions in Java?
With the usual "just return error code/success" error details may be lost before a program can determine it should log/report error.
Imagine a code similar to this:
err B()
{
if (read(a/b/c/U.user) != OK) {
return read_error; //which would be eaccess or we could return even e_cannot_read_user
}
if (is_empty(read_user.name)) {
// we could tell exactly what is missing here
return einval;
}
...
}
err A()
{
if (B() != OK) {
if (cannot_handle_B_failing()) {
return e_could_not_do_b;
}
}
...
}
main()
{
...
if (A() != OK) && (no_alternative_solution()) {
report error_returned_by_A;
wait_for_more_user_input();
}
}
Has anyone successfully tried some kind of nested error codes/messages in C for situations like that? Something that could report (in main) the fact that user name was missing or that file F can not be read due to invalid permissions.
Is there a library to support something like this?
I would suggest you to look at Apple's error handling guideline. It was designed for Objective-C and the main class there is NSError. They are using a userInfo dictionary (map) for holding detailed info about the error, and they have predefined NSUnderlyingErrorKey constant for holding underlying NSError object in that dictionary if needed.
So you can declare your own error struct for your code and implement similar solution.
e.g.
typedef struct {
int code;
struct Error *underlyingError;
char domain[0];
} Error;
You can then use domain field to categorize errors (by libs, files or functions as you want); code field to determine error itself and optional underlyingError field to find out what underlying error caused the error you received.
Each function may have its own independent, documented, and isolated set of errors. Like each function from the libc have their own documented set of possible return values and ERRNO codes.
The "root cause" is only an implementation detail, you just have to know "why" it failed.
In other words, A's documentation should not explain B, should not tell it uses B, nor tell about B's errors codes, it can have its own, locally meaningful, error codes.
Also while trying alternatives, you'll have to keep the origin failure codes (locally), so if the alternatives also fail you'll still be able to know what caused you to try them in the first place.
err B()
{
if (read(a/b/c/U.user) != OK) {
return read_error; //which would be eaccess or we could return even e_cannot_read_user
}
if (is_empty(read_user.name)) {
// we could tell exactly what is missing here
return einval;
}
...
}
err A()
{
if ((b_result = B()) != OK) {
// Here we understand b_result as we know B,
// but outside of we will no longer understand it.
// It means that we have to map B errors
// to semantically meaningful A errors.
if (cannot_handle_B_failing()) {
if (b_result == …)
return e_could_not_do_b_due_to_…;
else if (b_result == …)
return e_could_not_do_b_due_to_…;
else
return e_could_not_do_b_dont_know_why;
}
}
...
}
main()
{
...
if ((a_result = A()) != OK) && (no_alternative_solution()) {
// Here, if A change its implementation by no longer calling B
// we don't care, it'll still work.
report a_result;
wait_for_more_user_input();
}
}
It's costly to map B's errors to A's errors, but there's a profit: when B will change its implementation, it won't break all A's call sites.
This semantical mapping may look useless at first ("I'll map a "permission denied" to a "permission denied"...) but has to be adapted to the current level of abstraction, typically from a "cannot open file" to an "cannot open configuration", like:
err synchronize(source, dest, conf) {
conf_file = open(conf);
if (conf == -1)
{
if (errno == EACCESS)
return cannot_acces_config;
else
return unexpected_error_opening_config_file;
}
if (parse(config_file, &config_struct) == -1)
return cannot_parse_config;
source_file = open(source);
if (source_file == -1)
{
if (errno == EACCESS)
return cannot_open_source_file;
else
return unexpected_error_opening_source_file;
}
dest_file = open(dest);
if (dest == -1)
{
if (errno == EACCESS)
return cannot_open_dest_file;
else
return unexpected_error_opening_dest_file;
}
}
And it does not have to be a one to one mapping. If you map errors one-to-one, for a depth of three functions, with three calls each, with the deeper function having 16 different possible errors, it'll map to 16 * 3 * 3 = 144 different distinct errors, which is just a maintenance hell for everyone (imagine your translators having to translate 144 error messages too… and your documentation listing and explaining them all, for a single function).
So, do not forget that functions have to abstract the work they're doing and also abstract the errors they encounter, to an understandable, locally meaningful, set of errors.
Finally, in some cases, even by keeping a whole stack trace of what happened, you won't be able to deduce the root cause of an error: Imagine a configuration reader have to look for configuration in 5 different places, it may encounter 3 "file not found", one "permission denied", and another "file not found", so it will return "Configuration not found". From here, nobody but the user can tell why it failed: Maybe the user did a typo in the first file name, and the permission denied was totally expected, or maybe the first three files are not meant to exist but the user did a chmod error on the 4th one.
In those cases, the only way to help the user debugging the issue is to provide verbose flags, like "-v" , "-vv", "-vvv", … each time adding a new level of debugging details, up to a point where the user will be able to see in the logs that the configuration had 5 places to check, checked the first one, got a file not found, and so on, and deduce where the program diverged from its intentions.
The solution we use in one of our project is to pass special error-handling struct thru full stack of functions. This allows to get original error and message on any higher level. Using this solution your example will look like:
struct prj_error {
int32_t err;
char msg[ERR_MAX_LEN];
};
prj_error_set(struct prj_error *err, int errorno, const char *fmt, ...); /* implement yourselves */
int B(struct prj_error *err)
{
char *file = "a/b/c/U.user";
if (custom_read(file) != OK) {
prj_error_set(err, errno, "Couldn't read file \"%s\". Error: %s\n",
file, strerror(errno));
return err->err;
}
if (is_empty(read_user.name)) {
prj_error_set(err, -ENOENT, "Username in file \"%s\" is empty\n",
file);
return err->err;
}
...
}
int A(struct prj_error *err)
{
if (B(err) != OK) {
if (cannot_handle_B_failing()) {
return err.err;
}
}
...
}
main()
{
struct prj_error err;
...
if (A(&err) != OK) && (no_alternative_solution()) {
printf("ERROR: %s (error code %d)\n", err.msg, err.err);
wait_for_more_user_input();
}
}
Good luck!
It's not a full solution, but what I tend to do is to have each compilation unit (C file) have unique return codes. It may have a couple of externally visible functions and a bunch of static (only locally visible) functions.
Then within the C file, the return values are unique. Within the C file, if it makes sense, I also decide if I need to log something. Whatever is returned, the caller can know exactly what went wrong.
None of this is great. OTOH exceptions also have wrinkles. When I code in C++ I don't miss C's return handling, but weirdly enough, when I code in C, I can not say with a straight face I miss exceptions. They add complexity in their own way.
My programs may look like this:
some_file.c:
static int _internal_function_one_of_a_bunch(int h)
{
// blah code, blah
if (tragedy_strikes()) {
return 13;
}
// blah more code
return 0; // OK
}
static int _internal_function_another(int h)
{
// blah code, blah
if (tragedy_strikes_again()) {
return 14;
}
if (knob_twitch() != SUPER_GOOD) {
return 15;
}
// blah more code
return 0; // OK
}
// publicly visible
int do_important_stuff(int a)
{
if (flight_status() < NOT_EVEN_OK) {
return 16;
}
return _internal_function_another(a) ||
_internal_function_one_of_a_bunch(2 * a) ||
0; // OK
}

C (C89) optimization with passing error codes

I am writing a shared/dynamic library (https://github.com/zsawyer/mumble-LinkAPI).
For this I will provide some basic accessors (get, set and update) for the data in a shared memory struct (cannot be changed as it is externally defined).
There are quite a number of accessors my library will provide.
Getter and Setter methods are OK, imo, but my update functions give me trouble. They all pretty much will look the same - I smell a lot of code redundancy.
Note: I want to stick to C89! That is: I do not want to use C++ nor C99, C11.
Updating name is exemplary for almost all other update functions (arguments will vary):
ErrorCode updateName(wchar_t name[MAX_NAME_LENGTH]) {
ErrorCode err = setName(name);
if (err != ERROR_CODE_NO_ERROR) {
return err;
}
return commit();
}
The error codes are defined in an enum:
/**
* error codes hinting at the root cause of a failure
*/
typedef enum {
/** no error */
ERROR_CODE_NO_ERROR = 0,
/** win32 specific: OpenFileMappingW failed to return a handle */
ERROR_CODE_WIN32_NO_HANDLE = 1,
/** win32 specific: MapViewOfFile failed to return a structure */
ERROR_CODE_WIN32_NO_STRUCTURE = 2,
/** unix specific: shm_open returned a negative integer */
ERROR_CODE_UNIX_NO_HANDLE = 3,
/** unix specific: mmap failed to return a structure */
ERROR_CODE_UNIX_NO_STRUCTURE = 4,
/** shared memory was not initialized */
ERROR_CODE_NO_MEMORY_WAS_INITIALIZED = 5
} ErrorCode;
I want to pass the original error code all the way up to the caller of the library function while avoiding to write the same function x-times just with a different setXxx-function and parameter. I feel there should be an easier way.
Question: How can I rewrite the update functions to pass the ErrorCode and still reduce the code redundancy and make the function more readable/shorter?
Aside from that I caught myself at starting to copy a large part of the function documentation comments (i.e. that of set is 95% the same as of update methods), if you know any best practice to avoid that too, let me know.
How about defining a function
int commit_if_ok(int prev_error_code)
{
if (prev_error_code != ERROR_CODE_NO_ERROR)
return prev_error_code;
else
return commit();
}
and using it as:
ErrorCode updateName(wchar_t name[MAX_NAME_LENGTH])
{
return commit_if_ok(setName(name));
}
Note that commit_if_ok may be an inline function if your particular compiler has directives to allow that (many older compilers don't, but some do), but it should not be a macro because it uses its argument twice.

Resources