3

I'm trying to mock a fn say foo using

#ifdef UT_TEST
    void foo(void)  __attribute__ ((weak, alias ("foo_impl")));
#else
    void foo(void);
#endif

However, is there a way to do this @ runtime instead of compile time? I cannot use C++, for historical reasons.

kgunjikar
  • 455
  • 4
  • 17
  • Why do you need to do it at run time? – Fantastic Mr Fox Sep 13 '16 at 20:13
  • Have you tried preloading a shared library that provides the `foo()` mock? – John Bollinger Sep 13 '16 at 20:16
  • @Ben Reason for runtime, lets say I mock malloc(). Then I call foo with malloc() mocked.After that I want to call bar() with normal malloc(), how do I change the behavior? – kgunjikar Sep 13 '16 at 20:33
  • @John , Are you suggesting do a dlopen() and then check using dlysm()? – kgunjikar Sep 13 '16 at 20:36
  • 1
    @kgunjikar, no. See [What is the LD_PRELOAD trick?](http://stackoverflow.com/questions/426230/what-is-the-ld-preload-trick) – John Bollinger Sep 13 '16 at 20:43
  • 1
    In Linux, the problem you are trying to solve with this approach is better solved using a `STT_GNU_IFUNC` resolver function, via the [`ifunc` function attribute](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-g_t_0040code_007bifunc_007d-function-attribute-3263). – Nominal Animal Sep 13 '16 at 20:43
  • @Nominal Animal ifunc resolves the symbol once. Its not truly dynamic. For example, https://gcc.gnu.org/ml/gcc-help/2012-03/msg00209.html, if set global =0 in main, foo still will point to f1 – kgunjikar Sep 14 '16 at 21:00
  • `ifunc` function attribute is used in order to select an implementation -- function variant -- before the process `main()` starts. If you want to modify the behaviour multiple times at runtime, you will need to use a wrapper. Most libraries with functions intended to be easily interposed if necessary, including the GNU C library, implement each particular function with a library-specific name (say, `__libc_write`), and have the easily-interposed function be a weak alias (say, `write`). Nevertheless, even the internal library calls use `write`. – Nominal Animal Sep 14 '16 at 23:14
  • When interposing functions using e.g. the `LD_PRELOAD` mechanism (it isn't a trick!), Linux provides [`dlsym(RTLD_NEXT, "write")`](http://man7.org/linux/man-pages/man3/dlsym.3.html) to look up the *next* address for `write` (i.e., the symbol that would be used if this dynamic link object had not interposed it), allowing the interposed version of `write()` to internally use the original `write()` via a function pointer. This is a standard Linux feature, that anyone writing dynamic libraries for use in others' programs in Linux should be familiar with. – Nominal Animal Sep 14 '16 at 23:19

1 Answers1

1

In the past I've mostly seen this problem solved at the build system level instead, which I feel is a cleaner solution. Doing it this way allows to avoid most ifdefs and instead work with full files. In make, it might look something like this:

OBJS += file1.o file2.o
ifeq ($(UNIT_TEST),y)
OBJS += dummy_implementation.o
else
OBJS += real_implementation.o
endif

myprog: $(OBJS)

or in more classic make idiom:

OBJS-y += file1.o file2.o
OBJS-$(UNIT_TEST) += dummy_implementation.o
OBJS-$(REAL_BUILD) += real_implementation.o
OBJS = $(OBJS-y)

myprog: $(OBJS)

dummy_implementation.c and real_implementation.c would share a header file in this case.

jforberg
  • 6,537
  • 3
  • 29
  • 47