I'm trying to use the cmocka unit test framework which suggests to use weak linking to be able to select a user-defined implementation over the actual implementation of a function. In my environment I have a shared object which I want to unit test. I've implemented the unit tests in a separate file which I compile and link to the shared object. My problem is that calling a function bar
in the shared object which in turn calls a function foo
in that shared object always leads to the real implementation of foo
and not the custom one. I've created a simplified implementation of the shared object and of the unit test.
The shared library, a.c
:
#include <stdio.h>
void foo(void); __attribute__((weak))
void bar(void); __attribute__((weak))
void foo(void) {
printf("called real foo\n");
}
void bar(void) {
printf("called real bar calling\n");
foo();
}
The unit test, b.c
:
#include <stdio.h>
#include <stdbool.h>
bool orig_foo;
bool orig_bar;
void __wrap_foo(void) {
printf("in foo wrapper\n");
if (orig_foo)
__real_foo();
else
printf("called wrapped foo\n");
}
void __wrap_bar() {
printf("in bar wrapper\n");
if (orig_bar)
__real_bar();
else
printf("called wrapped bar\n");
}
int main(void) {
orig_bar = true;
orig_foo = false;
printf("calling foo from main\n");
foo();
printf("\n");
printf("calling bar from main\n");
bar();
return 0;
}
And finally, the Makefile
:
all: a.out
a.out: b.c a.so
gcc -Wall b.c a.so -Wl,--wrap=foo -Wl,--wrap=bar
a.so: a.c
gcc -Wall -c a.c -shared -o a.so
clean:
rm -f a.so a.out
Running a.out
produces the following output:
# ./a.out
calling foo from main
in foo wrapper
called wrapped foo
calling bar from main
in bar wrapper
called real bar
called real foo
From main, the direct call to foo
results in __wrap_foo
being called, as expected.
Next, I call bar
from main which correctly results in __wrap_bar
being called, where I redirect the call to the real implementation of bar
(__real_bar
). bar
then calls foo
but the real implementation is used, not the wrapped one. Why isn't the wrapped implementation of foo
called in this case? It looks like the issue is related to from where the function call originates.
In function bar
, if I replaced the called to foo
with __wrap_foo
I do get the expected behaviour however I don't think that this is an elegant solution.
I've managed to bypass this problem using normal linking and dlopen(3)
and friends however I'm curious as to why weak linking isn't working in my case.
a.so
is completely broken. You create an object file instead of a shared library. – Litcha.so
froma.o
(compiled with-fpic
) but I get the exact same behaviour. – Wallaroofoo
andbar
into separate files and compile everything together. – Wallaroo