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.
}
I have a compiler warning I would like to get rid off.
warning: the argument to '__builtin_assume' has side effects that will be discarded [-Wassume]
C:\Keil_v5\ARM\ARMCLANG\Bin..\include\assert.h(72): note: expanded from macro 'assert'
define assert(e) ((e) ? (void)0 : _CLIBNS _aeabi_assert(e, _FILE__, _LINE__), (__ARM_PROMISE)((e)?1:0))
The idea is to have no warning when compiled with warning set to "pedantic".
The cause is a recently added pointer check function to my embedded code. The idea is to improve the following:
void foo(int* const val)
{ assert(val != NULL);
/*Use val etc.*/
}
to something along the lines of:
void foo(int* const val)
{ assert(checkPtr(val) == OK);
/*Use val etc.*/
}
This is because automatic variables are not zero intialised. Thus, it is likely that an uninitialised pointer will not be NULL. This is a coding mistake that I would like to detect (not necessarily my own doing), hence the checks. The following is not perfect, but does seem to pick up more pointer errors (not dangling ones unfortunately).
I have the following code in a header file to implement this:
#define INTERNAL_RAM_START ((uintptr_t)0x2000000UL)
#define INTERNAL_RAM_END (INTERNAL_RAM_START + (uintptr_t)0x20000UL)
#define INTERNAL_ROM_START ((uintptr_t)0x8000000UL)
#define INTERNAL_ROM_END (INTERNAL_ROM_START + (uintptr_t)0x100000UL)
typedef enum{OK, NOT_OK}Status_t;
static inline Status_t checkPtr(const void* const ptrToCheck)
{
if(ptr == NULL)
return NOT_OK;
const uintptr_t ptr = (uintptr_t)ptrToCheck;
if((ptr >= INTERNAL_RAM_START) && (ptr < INTERNAL_RAM_END))
return OK;
if((ptr >= INTERNAL_ROM_START) && (ptr < INTERNAL_ROM_END))
return OK;
return NOT_OK
}
I don't have any warnings with ARMCC 5.06 in my code. From what I can see, my checkPtr function does not have any side effects. It does not access any variables other than the pointer that was passed to it.
The documentation suggests that armclang supports the __attribute__ ((pure)) and __attribute__ ((const)) function attributes. These attributes are for functions that don't have any side effect, their return value is based on the input parameters. A pure function can also read global state, while a const function can only examine its function parameters.
Adding one of these attributes to your checkPtr declaration and definition should silence the warning.
I'm working on a macro that will support error handling.
#define Try(e, call) ( (e == OK) && ((e = call) != OK) )
It can be used as the expression of an if-statement:
if (Try(err, SomeFunction(foo, bar))) {
// Entered only if err was OK before the if-statement and SomeFunction()
// returned a non-OK value.
}
The function won't be called if err was already non-OK before the if-statement. After the if-statement err will be set to the return value of SomeFunction().
So far so good. However I also want to use the macro without an if-statement:
Try(err, SomeFunction(foo, bar));
In this case GCC gives the following warning:
warning: value computed is not used [-Wunused-value]
And that's what my question is about: how can I rewrite the macro such that GCC won't produce this warning. I know the warning can be disabled with a flag (but I want to keep it enabled for other code) or by casting the result explicitly to void. The following statement code won't produce the warning:
(void) Try(err, SomeFunction(foo, bar));
But it's far from ideal to prefix each Try() with a void cast. Any suggestions?
You can use the ternary operator like this:
( (e == OK) ? ((e = call) != OK) : (e == OK) )
I'd go for something like this
inline
bool notOK(int err) {
return err != OK;
}
#define Try(e, call) ( !notOK(e) && notOK(e = call) )
Usually compilers don't complain about function return values that are not used.
For debugging purposes it might be necessary also to add an "instantiation"
bool notOK(int err);
in a .c file.
Just an idea.
static inline int identity (int x) { return x; }
#define Try(e, call) (identity ((e == OK) && ((e = call) != OK)))
You may want to #define inline __inline__ or #define inline /*nothing*/ for non-gcc compilers.
I would like to force a functions parameters to accept only specific definitions. For example, consider #define OUTPUT 1, #define INPUT 0 and void restrictedFunction(int parameter); .
How would I force restrictedFunction(int parameter) to accept only OUTPUT or INPUT?
I would also like to take into consideration that another definition may have the same value, for example, #define LEFT 1 and #define RIGHT 0.
So in this case I would like restrictedFunction(int parameter) to be able to accept only OUTPUT and INPUT specifically.
typedef enum { INPUT = 0, OUTPUT = 1 } IO_Type;
void restrictedFunction(IO_Type parameter) { ... }
It doesn't absolutely force the use of the values (the compiler will let someone write restrictedFunction(4)), but it is about as good as you'll get.
If you truly want to force the correct type, then:
typedef enum { INPUT = 0, OUTPUT = 1 } IO_Type;
typedef struct { IO_Type io_type } IO_Param;
void restrictedFunction(IO_Param parameter) { ... }
In C99 or later, you could call that with:
restrictedFunction((IO_Param){ INPUT });
This is a compound literal, creating a structure on the fly. It is not entirely clear that the structure type really buys you very much, but it will force the users to think a little and may improve the diagnostics from the compiler when they use it wrong (but they can probably use restrictedFunction((IO_Param){ 4 }); still).
What this means is that your restrictedFunction() code should be ready to validate the argument:
void restrictedFunction(IO_Type io_type)
{
switch (io_type)
{
case INPUT:
...do input handling...
break;
case OUTPUT:
...do output handling...
break;
default:
assert(io_type != INPUT && io_type != OUTPUT);
...or other error handling...
break;
}
}
You could use an enum.
typedef enum TrafficDirection { INPUT = 0, OUTPUT = 1 } TrafficDirection;
restrictedFunction(TrafficDirection direction);
of course, this isn't perfect. You can still pass any int to it as long as you use a cast.
restrictedFunction((TrafficDirection) 4);
You don't get quite as much protection as you might like, but you can do:
enum func_type { INPUT, OUTPUT };
void restrictedFunction( enum func_type parameter );
You can use a wrapper to validate the argument:
#define restrictedFunction(x) do { \
static_assert((x) == INPUT || (x) == OUTPUT); \
assert(!strcmp(#x, "INPUT") || !strcmp(#x, "OUTPUT")); \
restrictedFunction(x); \
} while(0)
Notes:
This assumes restrictedFunction() returns a void. If it returns a value which you actually use, you'll need something like gcc's compound statement http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html. Or--better--you can use BUILD_BUG_ON_ZERO (see What is ":-!!" in C code?), which I keep forgetting about, because it doesn't seem to work with C++.
The do ... while(0) is to "swallow the semi-colon"; not really relevant here.
static_assert() is a compile-time assert; there are many variants available. Here is a link to one, https://stackoverflow.com/a/9059896/318716, if you don't have your own handy.
assert() is the standard run-time assert.
With gcc 4.1.2, and my version of static_assert(), you can replace the run-time assert() with a compile-time assert when the two !strcmp()'s are replaced with ==; see example below. I haven't tested this with other compilers.
x is only used once in the macro expansion, since the first four references are only used at compile-time.
When your actually define your function, you'll have to add parentheses to disable the macro expansion, as in:
void (restrictedFunction)(int x){ ... }
Also, if your code has a special case (whose code doesn't?) where you need to call restrictedFunction() with the argument foo, you'll need to write:
(restrictedFunction)(foo);
Here is a complete example, which puts a wrapper around the standard library function exit():
#include <stdlib.h>
#define CONCAT_TOKENS(a, b) a ## b
#define EXPAND_THEN_CONCAT(a,b) CONCAT_TOKENS(a, b)
#define ASSERT(e) enum{EXPAND_THEN_CONCAT(ASSERT_line_,__LINE__) = 1/!!(e)}
#define ASSERTM(e,m) enum{EXPAND_THEN_CONCAT(m##_ASSERT_line_,__LINE__)=1/!!(e)}
#define exit(x) do { \
ASSERTM((x) == EXIT_SUCCESS || (x) == EXIT_FAILURE, value); \
ASSERTM(#x == "EXIT_SUCCESS" || #x == "EXIT_FAILURE", symbol); \
exit(x); \
} while(0)
int main(void) {
exit(EXIT_SUCCESS); // good
exit(EXIT_FAILURE); // good
exit(0); // bad
exit(3); // doubly bad
}
If I try to compile it, I get:
gcc foo.c -o foo
foo.c: In function 'main':
foo.c:17: error: enumerator value for 'symbol_ASSERT_line_17' is not an integer constant
foo.c:18: warning: division by zero
foo.c:18: error: enumerator value for 'value_ASSERT_line_18' is not an integer constant
foo.c:18: error: enumerator value for 'symbol_ASSERT_line_18' is not an integer constant
I was thinking today about the try/catch blocks existent in another languages. Googled for a while this but with no result. From what I know, there is not such a thing as try/catch in C. However, is there a way to "simulate" them?
Sure, there is assert and other tricks but nothing like try/catch, that also catch the raised exception. Thank you
C itself doesn't support exceptions but you can simulate them to a degree with setjmp and longjmp calls.
static jmp_buf s_jumpBuffer;
void Example() {
if (setjmp(s_jumpBuffer)) {
// The longjmp was executed and returned control here
printf("Exception happened here\n");
} else {
// Normal code execution starts here
Test();
}
}
void Test() {
// Rough equivalent of `throw`
longjmp(s_jumpBuffer, 42);
}
This website has a nice tutorial on how to simulate exceptions with setjmp and longjmp
http://www.di.unipi.it/~nids/docs/longjump_try_trow_catch.html
You use goto in C for similar error handling situations.
That is the closest equivalent of exceptions you can get in C.
Ok, I couldn't resist replying to this. Let me first say I don't think it's a good idea to simulate this in C as it really is a foreign concept to C.
We can use abuse the preprocessor and local stack variables to give use a limited version of C++ try/throw/catch.
Version 1 (local scope throws)
#include <stdbool.h>
#define try bool __HadError=false;
#define catch(x) ExitJmp:if(__HadError)
#define throw(x) {__HadError=true;goto ExitJmp;}
Version 1 is a local throw only (can't leave the function's scope). It does rely on C99's ability to declare variables in code (it should work in C89 if the try is first thing in the function).
This function just makes a local var so it knows if there was an error and uses a goto to jump to the catch block.
For example:
#include <stdio.h>
#include <stdbool.h>
#define try bool __HadError=false;
#define catch(x) ExitJmp:if(__HadError)
#define throw(x) {__HadError=true;goto ExitJmp;}
int main(void)
{
try
{
printf("One\n");
throw();
printf("Two\n");
}
catch(...)
{
printf("Error\n");
}
return 0;
}
This works out to something like:
int main(void)
{
bool HadError=false;
{
printf("One\n");
{
HadError=true;
goto ExitJmp;
}
printf("Two\n");
}
ExitJmp:
if(HadError)
{
printf("Error\n");
}
return 0;
}
Version 2 (scope jumping)
#include <stdbool.h>
#include <setjmp.h>
jmp_buf *g__ActiveBuf;
#define try jmp_buf __LocalJmpBuff;jmp_buf *__OldActiveBuf=g__ActiveBuf;bool __WasThrown=false;g__ActiveBuf=&__LocalJmpBuff;if(setjmp(__LocalJmpBuff)){__WasThrown=true;}else
#define catch(x) g__ActiveBuf=__OldActiveBuf;if(__WasThrown)
#define throw(x) longjmp(*g__ActiveBuf,1);
Version 2 is a lot more complex but basically works the same way. It uses a
long jump out of the current function to the try block. The try block then
uses an if/else to skip the code block to the catch block which check the local
variable to see if it should catch.
The example expanded again:
jmp_buf *g_ActiveBuf;
int main(void)
{
jmp_buf LocalJmpBuff;
jmp_buf *OldActiveBuf=g_ActiveBuf;
bool WasThrown=false;
g_ActiveBuf=&LocalJmpBuff;
if(setjmp(LocalJmpBuff))
{
WasThrown=true;
}
else
{
printf("One\n");
longjmp(*g_ActiveBuf,1);
printf("Two\n");
}
g_ActiveBuf=OldActiveBuf;
if(WasThrown)
{
printf("Error\n");
}
return 0;
}
This uses a global pointer so the longjmp() knows what try was last run.
We are using abusing the stack so child functions can also have a try/catch block.
Using this code has a number of down sides (but is a fun mental exercise):
It will not free allocated memory as there are no deconstructors being called.
You can't have more than 1 try/catch in a scope (no nesting)
You can't actually throw exceptions or other data like in C++
Not thread safe at all
You are setting up other programmers for failure because they will likely not notice the hack and try using them like C++ try/catch blocks.
In C99, you can use setjmp/longjmp for non-local control flow.
Within a single scope, the generic, structured coding pattern for C in the presence of multiple resource allocations and multiple exits uses goto, like in this example. This is similar to how C++ implements destructor calls of automatic objects under the hood, and if you stick to this diligently, it should allow you for a certain degree of cleanness even in complex functions.
While some of the other answers have covered the simple cases using setjmp and longjmp, in a real application there's two concerns that really matter.
Nesting of try/catch blocks. Using a single global variable for your jmp_buf will make these not work.
Threading. A single global variable for you jmp_buf will cause all kinds of pain in this situation.
The solution to these is to maintain a thread-local stack of jmp_buf that get updated as you go. (I think this is what lua uses internally).
So instead of this (from JaredPar's awesome answer)
static jmp_buf s_jumpBuffer;
void Example() {
if (setjmp(s_jumpBuffer)) {
// The longjmp was executed and returned control here
printf("Exception happened\n");
} else {
// Normal code execution starts here
Test();
}
}
void Test() {
// Rough equivalent of `throw`
longjump(s_jumpBuffer, 42);
}
You'd use something like:
#define MAX_EXCEPTION_DEPTH 10;
struct exception_state {
jmp_buf s_jumpBuffer[MAX_EXCEPTION_DEPTH];
int current_depth;
};
int try_point(struct exception_state * state) {
if(current_depth==MAX_EXCEPTION_DEPTH) {
abort();
}
int ok = setjmp(state->jumpBuffer[state->current_depth]);
if(ok) {
state->current_depth++;
} else {
//We've had an exception update the stack.
state->current_depth--;
}
return ok;
}
void throw_exception(struct exception_state * state) {
longjump(state->current_depth-1,1);
}
void catch_point(struct exception_state * state) {
state->current_depth--;
}
void end_try_point(struct exception_state * state) {
state->current_depth--;
}
__thread struct exception_state g_exception_state;
void Example() {
if (try_point(&g_exception_state)) {
catch_point(&g_exception_state);
printf("Exception happened\n");
} else {
// Normal code execution starts here
Test();
end_try_point(&g_exception_state);
}
}
void Test() {
// Rough equivalent of `throw`
throw_exception(g_exception_state);
}
Again a more realistic version of this would include some way to store error information into the exception_state, better handling of MAX_EXCEPTION_DEPTH (maybe using realloc to grow the buffer, or something like that).
DISCLAIMER: The above code was written without any testing whatsoever. It is purely so you get an idea of how to structure things. Different systems and different compilers will need to implement the thread local storage differently. The code probably contains both compile errors and logic errors - so while you're free to use it as you choose, TEST it before using it ;)
This is another way to do error handling in C which is more performant than using setjmp/longjmp. Unfortunately, it will not work with MSVC but if using only GCC/Clang is an option, then you might consider it. Specifically, it uses the "label as value" extension, which allows you to take the address of a label, store it in a value and and jump to it unconditionally. I'll present it using an example:
GameEngine *CreateGameEngine(GameEngineParams const *params)
{
/* Declare an error handler variable. This will hold the address
to jump to if an error occurs to cleanup pending resources.
Initialize it to the err label which simply returns an
error value (NULL in this example). The && operator resolves to
the address of the label err */
void *eh = &&err;
/* Try the allocation */
GameEngine *engine = malloc(sizeof *engine);
if (!engine)
goto *eh; /* this is essentially your "throw" */
/* Now make sure that if we throw from this point on, the memory
gets deallocated. As a convention you could name the label "undo_"
followed by the operation to rollback. */
eh = &&undo_malloc;
/* Now carry on with the initialization. */
engine->window = OpenWindow(...);
if (!engine->window)
goto *eh; /* The neat trick about using approach is that you don't
need to remember what "undo" label to go to in code.
Simply go to *eh. */
eh = &&undo_window_open;
/* etc */
/* Everything went well, just return the device. */
return device;
/* After the return, insert your cleanup code in reverse order. */
undo_window_open: CloseWindow(engine->window);
undo_malloc: free(engine);
err: return NULL;
}
If you so wish, you could refactor common code in defines, effectively implementing your own error-handling system.
/* Put at the beginning of a function that may fail. */
#define declthrows void *_eh = &&err
/* Cleans up resources and returns error result. */
#define throw goto *_eh
/* Sets a new undo checkpoint. */
#define undo(label) _eh = &&undo_##label
/* Throws if [condition] evaluates to false. */
#define check(condition) if (!(condition)) throw
/* Throws if [condition] evaluates to false. Then sets a new undo checkpoint. */
#define checkpoint(label, condition) { check(condition); undo(label); }
Then the example becomes
GameEngine *CreateGameEngine(GameEngineParams const *params)
{
declthrows;
/* Try the allocation */
GameEngine *engine = malloc(sizeof *engine);
checkpoint(malloc, engine);
/* Now carry on with the initialization. */
engine->window = OpenWindow(...);
checkpoint(window_open, engine->window);
/* etc */
/* Everything went well, just return the device. */
return device;
/* After the return, insert your cleanup code in reverse order. */
undo_window_open: CloseWindow(engine->window);
undo_malloc: free(engine);
err: return NULL;
}
A quick google search yields kludgey solutions such as this that use setjmp/longjmp as others have mentioned. Nothing as straightforward and elegant as C++/Java's try/catch. I'm rather partial to Ada's exception handling myself.
Check everything with if statements :)
This can be done with setjmp/longjmp in C. P99 has a quite comfortable toolset for this that also is consistent with the new thread model of C11.
In C, you can "emulate" exceptions along with automatic "object reclamation" through manual use of if + goto for explicit error handling.
I often write C code like the following (boiled down to highlight error handling):
#include <assert.h>
typedef int errcode;
errcode init_or_fail( foo *f, goo *g, poo *p, loo *l )
{
errcode ret = 0;
if ( ( ret = foo_init( f ) ) )
goto FAIL;
if ( ( ret = goo_init( g ) ) )
goto FAIL_F;
if ( ( ret = poo_init( p ) ) )
goto FAIL_G;
if ( ( ret = loo_init( l ) ) )
goto FAIL_P;
assert( 0 == ret );
goto END;
/* error handling and return */
/* Note that we finalize in opposite order of initialization because we are unwinding a *STACK* of initialized objects */
FAIL_P:
poo_fini( p );
FAIL_G:
goo_fini( g );
FAIL_F:
foo_fini( f );
FAIL:
assert( 0 != ret );
END:
return ret;
}
This is completely standard ANSI C, separates the error handling away from your mainline code, allows for (manual) stack unwinding of initialized objects much like C++ does, and it is completely obvious what is happening here. Because you are explicitly testing for failure at each point it does make it easier to insert specific logging or error handling at each place an error can occur.
If you don't mind a little macro magic, then you can make this more concise while doing other things like logging errors with stack traces. For example:
#include <assert.h>
#include <stdio.h>
#include <string.h>
#define TRY( X, LABEL ) do { if ( ( X ) ) { fprintf( stderr, "%s:%d: Statement '%s' failed! %d, %s\n", __FILE__, __LINE__, #X, ret, strerror( ret ) ); goto LABEL; } while ( 0 )
typedef int errcode;
errcode init_or_fail( foo *f, goo *g, poo *p, loo *l )
{
errcode ret = 0;
TRY( ret = foo_init( f ), FAIL );
TRY( ret = goo_init( g ), FAIL_F );
TRY( ret = poo_init( p ), FAIL_G );
TRY( ret = loo_init( l ), FAIL_P );
assert( 0 == ret );
goto END;
/* error handling and return */
FAIL_P:
poo_fini( p );
FAIL_G:
goo_fini( g );
FAIL_F:
foo_fini( f );
FAIL:
assert( 0 != ret );
END:
return ret;
}
Of course, this isn't as elegant as C++ exceptions + destructors. For example, nesting multiple error handling stacks within one function this way isn't very clean. Instead, you'd probably want to break those out into self contained sub functions that similarly handle errors, initialize + finalize explicitly like this.
This also only works within a single function and won't keep jumping up the stack unless higher level callers implement similar explicit error handling logic, whereas a C++ exception will just keep jumping up the stack until it finds an appropriate handler. Nor does it allow you to throw an arbitrary type, but instead only an error code.
Systematically coding this way (i.e. - with a single entry and single exit point) also makes it very easy to insert pre and post ("finally") logic that will execute no matter what. You just put your "finally" logic after the END label.
Warning: the following is not very nice but it does the job.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
unsigned int id;
char *name;
char *msg;
} error;
#define _printerr(e, s, ...) fprintf(stderr, "\033[1m\033[37m" "%s:%d: " "\033[1m\033[31m" e ":" "\033[1m\033[37m" " ‘%s_error’ " "\033[0m" s "\n", __FILE__, __LINE__, (*__err)->name, ##__VA_ARGS__)
#define printerr(s, ...) _printerr("error", s, ##__VA_ARGS__)
#define printuncaughterr() _printerr("uncaught error", "%s", (*__err)->msg)
#define _errordef(n, _id) \
error* new_##n##_error_msg(char* msg) { \
error* self = malloc(sizeof(error)); \
self->id = _id; \
self->name = #n; \
self->msg = msg; \
return self; \
} \
error* new_##n##_error() { return new_##n##_error_msg(""); }
#define errordef(n) _errordef(n, __COUNTER__ +1)
#define try(try_block, err, err_name, catch_block) { \
error * err_name = NULL; \
error ** __err = & err_name; \
void __try_fn() try_block \
__try_fn(); \
void __catch_fn() { \
if (err_name == NULL) return; \
unsigned int __##err_name##_id = new_##err##_error()->id; \
if (__##err_name##_id != 0 && __##err_name##_id != err_name->id) \
printuncaughterr(); \
else if (__##err_name##_id != 0 || __##err_name##_id != err_name->id) \
catch_block \
} \
__catch_fn(); \
}
#define throw(e) { *__err = e; return; }
_errordef(any, 0)
Usage:
errordef(my_err1)
errordef(my_err2)
try ({
printf("Helloo\n");
throw(new_my_err1_error_msg("hiiiii!"));
printf("This will not be printed!\n");
}, /*catch*/ any, e, {
printf("My lovely error: %s %s\n", e->name, e->msg);
})
printf("\n");
try ({
printf("Helloo\n");
throw(new_my_err2_error_msg("my msg!"));
printf("This will not be printed!\n");
}, /*catch*/ my_err2, e, {
printerr("%s", e->msg);
})
printf("\n");
try ({
printf("Helloo\n");
throw(new_my_err1_error());
printf("This will not be printed!\n");
}, /*catch*/ my_err2, e, {
printf("Catch %s if you can!\n", e->name);
})
Output:
Helloo
My lovely error: my_err1 hiiiii!
Helloo
/home/naheel/Desktop/aa.c:28: error: ‘my_err2_error’ my msg!
Helloo
/home/naheel/Desktop/aa.c:38: uncaught error: ‘my_err1_error’
Keep on mind that this is using nested functions and __COUNTER__. You'll be on the safe side if you're using gcc.
Redis use goto to simulate try/catch, IMHO it is very clean and elegant:
/* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success. */
int rdbSave(char *filename) {
char tmpfile[256];
FILE *fp;
rio rdb;
int error = 0;
snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid());
fp = fopen(tmpfile,"w");
if (!fp) {
redisLog(REDIS_WARNING, "Failed opening .rdb for saving: %s",
strerror(errno));
return REDIS_ERR;
}
rioInitWithFile(&rdb,fp);
if (rdbSaveRio(&rdb,&error) == REDIS_ERR) {
errno = error;
goto werr;
}
/* Make sure data will not remain on the OS's output buffers */
if (fflush(fp) == EOF) goto werr;
if (fsync(fileno(fp)) == -1) goto werr;
if (fclose(fp) == EOF) goto werr;
/* Use RENAME to make sure the DB file is changed atomically only
* if the generate DB file is ok. */
if (rename(tmpfile,filename) == -1) {
redisLog(REDIS_WARNING,"Error moving temp DB file on the final destination: %s", strerror(errno));
unlink(tmpfile);
return REDIS_ERR;
}
redisLog(REDIS_NOTICE,"DB saved on disk");
server.dirty = 0;
server.lastsave = time(NULL);
server.lastbgsave_status = REDIS_OK;
return REDIS_OK;
werr:
fclose(fp);
unlink(tmpfile);
redisLog(REDIS_WARNING,"Write error saving DB on disk: %s", strerror(errno));
return REDIS_ERR;
}
If you're using C with Win32, you can leverage its Structured Exception Handling (SEH) to simulate try/catch.
If you're using C in platforms that don't support setjmp() and longjmp(), have a look at this Exception Handling of pjsip library, it does provide its own implementation
After studying the answers given above, I set up a system that automatically handles nested exceptions well. Here is the code I wrote to test my system:
#include "MyOtherTricks.h"
#include "Exceptions.h"
void Testing_InnerMethod();
void Testing_PossibleExceptionThrower();
void TestExceptionHandling()
{
try
{
Testing_InnerMethod();
Say("The inner method exited without an exception.");
}
catch (Exception)
{
Say("I caught an Exception that the inner method did not catch.");
}
end_try
}
void Testing_InnerMethod()
{
try
{
Say("I am in a try block.");
Testing_PossibleExceptionThrower();
Say("The possible exception thrower didn't throw an exception.");
}
catch (ExceptionSubtype1)
Say("I caught an exception, subtype 1.");
catch (ExceptionSubtype2)
{
Say("I caught an exception, subtype 2.");
Say("I will now rethrow it.");
throw(exception);
}
end_try
}
void Testing_PossibleExceptionThrower()
{
Say("Here is the possible exception thrower.");
throw(new(ExceptionSubtype2)); // To further test exception handling, replace ExceptionSubtype2 in this line with Exception or ExceptionSubtype1, or comment out this line entirely.
Say("No, I won't throw an exception!");
}
The example code relies on two files, Exceptions.h and Exceptions.c. Here is Exceptions.h:
#include <setjmp.h>
extern jmp_buf* Exception_Handler;
#define try do \
{ \
jmp_buf* outerExceptionHandler = Exception_Handler; \
jmp_buf exceptionHandler; \
Exception_Handler = &exceptionHandler; \
Exception exception = (Exception)setjmp(exceptionHandler); \
if (exception != 0) Exception_Handler = outerExceptionHandler; \
if (exception == 0) \
{ \
// The try block goes here. It must not include a return statement or anything else that exits the try...end_try block, because then the outer exception handler will not be restored.
#define catch(exceptionType) Exception_Handler = outerExceptionHandler; \
} \
else if (Object_IsSomeTypeOf(exception, exceptionType)) \
{
// The catch block goes here. It may include a return statement or anything else that exits the try...end_try block. A break statement will exit only the try...end_try block.
#define end_try } \
else \
throw(exception); \
} while(0);
void throw(Exception exception);
And here is Exceptions.c:
#include "MyOtherTricks.h"
#include "Exceptions.h"
jmp_buf* Exception_Handler = 0;
void throw(Exception exception)
{
if (Exception_Handler == 0) FailBecause("Uncaught exception.");
longjmp(*Exception_Handler, (int)exception);
}
Note that this code references some additional methods that I'm not including here (because class inheritance in C is off-topic). To make this code work for you, you'll have to understand this code well enough to replace a few things. In particular, if you want to distinguish between different types of exceptions, you'll need to realize that this code assumes that Object_IsSomeTypeOf(new(ExceptionSubtype1), Exception) returns true and Object_IsSomeTypeOf(new(ExceptionSubtype1), ExceptionSubtype2) returns false, and you'll need to either make your own version of my Object_IsSomeTypeOf macro or replace it with something else.
Perhaps not a major language (unfortunately), but in APL, theres the ⎕EA operation (stand for Execute Alternate).
Usage:
'Y' ⎕EA 'X'
where X and Y are either code snippets supplied as strings or function names.
If X runs into an error, Y (usually error-handling) will be executed instead.