I very often write tests to my programs to make sure they work 100% of the time under any circumstances (so that later I don't have to spend hours debugging them).
However, all my tests so far were only testing the lines of code that I can reach under normal circumstances, so for instance I did not test what would happen if malloc() failed. I really want to do that too though, so recently I began experimenting and seeking answers about how to override any function so that it returns any predefined value and possibly sets errno to some value.
I learned about dlsym, LD_PRELOAD, and --wrap for linker. So far, I've had many successes with dlsym, even overriding malloc() and it wouldn't fall into an infinite loop, however Valgrind that I'm using to find memory leaks seems to happily ignore any functions I wrap with dlsym and so for instance malloc() starts acting normally when I don't want it to under Valgrind (and so returning NULL artificially doesn't work).
LD_PRELOAD is pretty much used in conjunction with dlsym, it doesn't really do anything on its own.
--wrap is nice and all, but its flaw is that you need to know the functions you want to override for every file. That is tiresome - with dlsym I can choose the functions in my code and that's it, but --wrap will make my Makefile significantly more complicated.
I've also tried using libc's hidden definitions (__libc_malloc(), __libc_function_name() in general) to override the weak symbols of malloc(), strxxx() and other functions that Valgrind likes to override and then using dlsym for everything else, kind of like so:
void* __libc_malloc(size_t);
void* malloc(size_t size) {
if(malloc_fail) {
errno = ENOMEM;
return NULL;
}
return __libc_malloc(size);
}
But then again, Valgrind would happily override this malloc implementation as well and leave me with no options at all.
I've also tried switching my memory leak detector to something like libasan (gcc -fsanitize=address), but unfortunately I have a very terrible experience with any sanitizers that come with gcc, because of their buggy implementation that for instance crashes when using pthread_cancel() (like here), and turns out my code needs to test some pthread functions awell, because I am wrapping them in my own functions and structures and stuff.
Is there any other way to trigger erroneous code paths? Am I doing something wrong?