Using callback functions for error handling in C - c

I have been thinking about the difficulty incurred with C error handling.. like who actually does
if(printf("hello world")==-1){exit(1);}
But you break common standards by not doing such verbose, and usually useless coding. Well what if you had a wrapper around the libc? like so you could do something like..
//main...
error_catchall(my_errors);
printf("hello world"); //this will automatically call my_errors on an error of printf
ignore=1; //this makes it so the function will return like normal and we can check error values ourself
if(fopen.... //we want to know if the file opened or not and handle it ourself.
}
int my_errors(){
if(ignore==0){
_exit(1); //exit if we aren't handling this error by flagging ignore
}
return 0;
//this is called when there is an error anywhere in the libc
}
...
I am considering making such a wrapper as I am synthesizing my own BSD licensed libc(so I already have to touch the untouchable..), but I would like to know what people think about it..
would this actually work in real life and be more useful than returning -1?

during this years I've seen several attempts to mimics try/catch in ANSI C:
http://simgrid.gforge.inria.fr/doc/group__XBT__ex.html
http://llg.cubic.org/trycatch/
I think that try/catch approach is more simple than your.

But how would you be able to catch the error when it was expected? For example I might expect a file open to fail and want to deal with it in code instead of the generic error catcher.
To do this you would need two versions of every function. One that trapped errors and one the returns errors.
I did something like this long ago without modifying the library. I just created wrapper functions for common calls that did error checking. So my errchk_malloc call checked the return and raised an error if the allocation failed. Then I just used this version everywhere in place of the built in malloc.

if the goal is to exit cleanly as soon as you encounter an error that's ok... but if you want to do a minimum of error recovery, i can't see how your approach is useful...
To avoid this kind of problem, I sometimes use LD_PRELOAD_PATH to integrate my error management (only for my own projects since this is not a really good practice...)

Do you really want to change the standard behaviors of your LIBC ? You could add a few extensions around common functions.
For example, Gnome uses g_malloc and g_try_malloc. The former will abort on failure while the later will simply yield a null-pointer like malloc.

Related

Is there a Windows API memory allocator/deallocator I can use that will just give me an error code if something goes wrong & in a cross-compiler way?

This is probably a crazy question but:
For the purposes of debugging and error handling I'd like to be able to make a note of why an allocation or free call failed. I'd like the same code to be compilable by both Microsoft's C compilers and MinGW-w64 (but not other MinGWs).
I could use malloc()/realloc()/free() but they don't provide any defined method of getting an error other than ENOMEM. Or is it safe to assume that the only reason malloc() can fail is lack of memory, which HeapAlloc() and others seems to disagree with? (This will also stop being an option if I choose not to use the C runtime in any future DLLs.) Or is it safe to assume that errno has any other error code? I would need to check my standards again...
I could also use HeapAlloc()/HeapReAlloc()/HeapFree(), but they don't return a last-error code. Instead, they can be made to throw an exception, which you are supposed to catch with a __try block... which is not supported by MinGW. libseh is not an option here; my programs and DLLs should be freestanding. I'm going to assume it is not safe to assume that the only reason it can fail when set to not throw an exception is out of memory because heap corruption is listed as a possibility; is this correct?
I tried using LocalAlloc()/LocalReAlloc()/LocalFree() but it failed to allocate more than a 256-byte-or-so structure and 2 ints, returning ERROR_NOT_ENOUGH_MEMORY.
There's no VirtualReAlloc(), so I assume I would need to write my own malloc() implementation if I go the VirtualAlloc() route.
Or am I just being crazy about all this?
And what about other allocators that I would be required to use, such as SysAllocString(); would it be safe to assume those can only ever fail because of out of memory?
Thanks.

Error Code Handling

Are there any standards for error code handling? What I mean by this is not how a particular error event is handled but what is actually returned in the process. An example of this would be when an error in opening a file is identified. While the open() function may return its own value, the function that called the open() function may return a different value.
I don't think ther's a standard, all errors must be detected and handled (the caller should always handle errors).
in Unix in general:
the standard C library for exemple always return -1 on fail and set the global variable errno to the correct value.
Some libraries for example return NULL for inexistant field rather than aborting.
You should always return as much useful information as possible.
Hope this help.
Regards.
It sounds entirely context dependent to me. In some cases it's even advisable to just abort() the whole process. The failing function is called from a program or library using its own coding standards, you should probably adhere to that.

How to cause sqlite3_initialize to fail

I have the following C code that uses sqlite3:
if(SQLITE_OK == sqlite3_initialize()) {
self->db_open_result = sqlite3_open(self->db_uri, &(self->db));
} else {
self->db_open_result = SQLITE_ERROR;
}
Obviously I have a pretty high confidence that the code is correct and will behave as expected. However, I am measuring code coverage of my unit tests using gcov/lcov and I'm curious about how I might get my coverage number to 100% in this case. Under normal circumstances sqlite3_initialize() is never going to fail, so the else clause will never execute.
Is there a way to cause this to fail that isn't totally disruptive?
You want your unit-tests to test your code. But you also want to know that all of your test code has been properly exercised. One way to do that is to use "mocking", i.e. you replace your actual libraries (such as SQLite) with fake, or "mock" libraries and then run your programs against these fake libraries.
Whether this library replacement is done at compile time or runtime is really incidental, but in C it's easier to do it at compile time. You can do this mocking by hand, or you can use a tool such as Cmock.
In the faked library, you then provoke various errors and failures. Notably, the faked library doesn't even have to do anything or even keep track of much or any state, you can often get quite far by returning "OK" or "FAIL".
Is there a way to cause this to fail that isn't totally disruptive?
For portability reasons you should verify function success. What's happens if you not installed SQLite library? You cannot initialize the library if that happens.
"If for some reason, sqlite3_initialize() is unable to initialize the library (perhaps it is unable to allocate a needed resource such as a mutex) it returns an error code..."
So, if you want portability check the error.

Returning error codes from a DLL

I have a dll with a c interface, the functions of which will return error codes, I will also provide an additional function that returns the last error. Does this sound sensible? can anyone point me at any examples that i can use as a template please?
"The last error" is not a very useful or reliable concept in the context of a DLL. What if the DLL is being used by several processes or threads?
I will also provide an additional function that returns the last error
That would entail having an errno-style global variable holding the last error, right? I'd advise against that, as it would make your library hard to use in a multithreaded application, unless you use thread-local storage. Still, if you want to do this, then the standard C library with its errno variable/macro would be a good example.
A simpler and, IMHO, better approach is to just return error codes and if necessary provide some functions that operate on your error codes; e.g., you might want to have a mylib_strerror to convert them to human-readable string representations. So, the usage would look like
int err = mylib_operation_that_might_fail();
if (err != 0) {
fprintf("%s\n", mylib_strerror(err));
exit(1);
}
A good example of this style is the getaddrinfo API specified in RFC 3493.

Learning C coming from managed OO languages

I am fairly comfortable coding in languages like Java and C#, but I need to use C for a project (because of low level OS API calls) and I am having some difficulty dealing with pointers and memory management (as seen here)
Right now I am basically typing up code and feeding it to the compiler to see if it works. That just doesn't feel right for me. Can anyone point me to good resources for me to understand pointers and memory management, coming from managed languages?
k&r - http://en.wikipedia.org/wiki/The_C_Programming_Language_(book)
nuff said
One of the good resources you found already, SO.
Of course you are compiling with all warnings on, don't you?
Learning by doing largely depends on the quality of your compiler and the warnings / errors he feeds you. The best in that respect that I found in the linux / POSIX world is clang. Nicely traces the origin of errors and tells you about missing header files quite well.
Some tips:
By default varibles are stored in the stack.
Varibles are passed into functions by Value
Stick to the same process for allocating and freeing memory. eg allocate and free in the same the function
C's equivalent of
Integer i = new Integer();
i=5;
is
int *p;
p=malloc(sizeof(int));
*p=5;
Memory Allocation(malloc) can fail, so check the pointer for null before you use it.
OS functions can fail and this can be detected by the return values.
Learn to use gdb to step through your code and print variable values (compile with -g to enable debugging symbols).
Use valgrind to check for memory leaks and other related problems (like heap corruption).
The C language doesn't do anything you don't explicitly tell it to do.
There are no destructors automatically called for you, which is both good and bad (since bugs in destructors can be a pain).
A simple way to get somewhat automatic destructor behavior is to use scoping to construct and destruct things. This can get ugly since nested scopes move things further and further to the right.
if (var = malloc(SIZE)) { // try to keep this line
use_var(var);
free(var); // and this line close and with easy to comprehend code between them
} else {
error_action();
}
return; // try to limit the number of return statements so that you can ensure resources
// are freed for all code paths
Trying to make your code look like this as much as possible will help, though it's not always possible.
Making a set of macros or inline functions that initialize your objects is a good idea. Also make another set of functions that allocate your objects' memory and pass that to your initializer functions. This allows for both local and dynamically allocated objects to easily be initialized. Similar operations for destructor-like functions is also a good idea.
Using OO techniques is good practice in many instances, and doing so in C just requires a little bit more typing (but allows for more control). Putters, getters, and other helper functions can help keep objects in consistent states and decrease the changes you have to make when you find an error, if you can keep the interface the same.
You should also look into the perror function and the errno "variabl".
Usually you will want to avoid using anything like exceptions in C. I generally try to avoid them in C++ as well, and only use them for really bad errors -- ones that aren't supposed to happen. One of the main reasons for avoiding them is that there are no destructor calls magically made in C, so non-local GOTOs will often leak (or otherwise screw up) some type of resource. That being said, there are things in C which provide a similar functionality.
The main exception like mechanism in C are the setjmp and longjmp functions. setjmp is called from one location in code and passed a (opaque) variable (jmp_buf) which can later be passed to longjmp. When a call to longjmp is made it doesn't actually return to the caller, but returns as the previously called setjmp with that jmp_buf. setjmp will return a value specified by the call to longjmp. Regular calls to setjmp return 0.
Other exception like functionality is more platform specific, but includes signals (which have their own gotchas).
Other things to look into are:
The assert macro, which can be used to cause program exit when the parameter (a logical test of some sort) fails. Calls to assert go away when you #define NDEBUG before you #include <assert.h>, so after testing you can easily remove the assertions. This is really good for testing for NULL pointers before dereferencing them, as well as several other conditions. If a condition fails assert attempts to print the source file name and line number of the failed test.
The abort function causes the program to exit with failure without doing all of the clean up that calling exit does. This may be done with a signal on some platforms. assert calls abort.

Resources