Wrapping System Calls
Page Contents
References
Why Wrap System Calls?
The main reason I like to do this is to check error handling in my code. I will wrap system functions so that I can simulate various possible errors that may occur and check that these are gracefully.
For example, lets say some resources have been allocated and then a system call fails. Have I cleaned up correctly? Below I offet a contrived example...
char *some_function() { char *buffer = malloc(...); if (!buffer) { // handle error } // ... // ... Do lots of work and ALLOCATE MORE RESOURCES // ... FILE *fh = fopen(...) if (!fh) { free(buffer); buffer = NULL; } // ... // ... return buffer; }
If, in the snippet above, fopen()
fails, I should free the buffer
. I can force the
function to fail by wrapping it with my own function that will return NULL
and set some desired
errno
and then check whether the function returns NULL
. Note, for memory leak detection
Valgrind or Dr. Memory would be the prefered options - this just checks the function logic flow.
How To Wrap System Calls
The GCC linker allows symbols to be linked to wrapper functions when the symbol in a translation unit is undefined.
What this means is that when you compile your .c
into a .o
and the object file
references fopen()
, the symbol before linkage will be undefined. It is the linker's job to link this
to the actual fopen()
function. So, what the linker can do is link this to some wrapper function that
you specify.
Lets say I write a test file and want to wrap fopen()
to test the above function, which I helpfully
called some_function()
. I would write the following in my test file:
FILE *fh __wrap_fopen(...) { errno = -E_SOME_CODE; return NULL; }
And in my makefile I would write:
my_test: $(TEST_OBJS) $(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $@ -Wl,--wrap=fopen
Maybe I only want fopen()
to fail at certain points in my test. Then in my test file I would write:
static bool some_flag = false; FILE *fh __wrap_fopen(...) { if (some_flag) { errno = -E_SOME_CODE; return NULL; } else { return __real_fopen(...); } } void test_some_feature() { some_function(); // My fopen wrap should work some_flag = true; some_function(); // Now I know my fopen wrap will fail and I can test condition is handled }
Using this strategy I can excercise some difficult-to-test paths through my code.