Kira
Kira

Reputation: 483

Removing functions included from a header from scope of the next files

In my project we are heavily using a C header which provides an API to comunicate to an external software. Long story short, in our project's bugs show up more often on the calling of the functions defined in those headers (it is an old and ugly legacy code).

I would like to implement an indirection on the calling of those functions, so I could include some profiling before calling the actual implementation.

Because I'm not the only person working on this project, I would like to make those wrappers in a such way that if someone uses the original implementations directly it should cause a compile error.

If those headers were C++ sources, I would be able to simply make a namespace, wrap the included files in it, and implement my functions using it (the other developers would be able to use the original implementation using the :: operator, but just not being able to call it directly is enough encapsulation to me). However the headers are C sources (which I have to include with extern "C" directive to include), so namespaces won't help me AFAIK.

I tried to play around with defines, but with no luck, like this:

#define my_func api_func
#define api_func NULL

What I wanted with the above code is to make my_func to be translated to api_func during the preprocessing, while making a direct call to api_func give a compile error, but that won't work because it will actually make my_func to be translated to NULL too.

So, basically, I would like to make a wrapper, and make sure the only way to access the API is through this wrapper (unless the other developers make some workaround, but this is inevitable). Please note that I need to wrap hundreds of functions, which show up spread in the whole code several times.

My wrapper necessarily will have to include those C headers, but I would like to make them leave scope outside the file of my wrapper, and make them to be unavailable to every other file who includes my wrapper, but I guess this is not possible in C/C++.

Upvotes: 0

Views: 210

Answers (3)

user3629249
user3629249

Reputation: 16530

There are two ways to wrap or override C functions in Linux:

Using LD_PRELOAD: 
There is a shell environment variable in Linux called LD_PRELOAD, 
which can be set to a path of a shared library, 
and that library will be loaded before any other library (including glibc).

Using ‘ld --wrap=symbol‘: 
This can be used to use a wrapper function for symbol. 
Any further reference to symbol will be resolved to the wrapper function. 

a complete writeup can be found at: http://samanbarghi.com/blog/2014/09/05/how-to-wrap-a-system-call-libc-function-in-linux/

Upvotes: 1

tofro
tofro

Reputation: 6073

You can do something like

[your wrapper's include file]

int origFunc1 (int x);
int origFunc2 (int x, int y);

#ifndef WRAPPER_IMPL
#define origFunc1 wrappedFunc1
#define origFunc2 wrappedFunc2
#else
int wrappedFunc1(int x);
int wrappedFunc2(int x, int y);
#endif

[your wrapper implementation]

#define WRAPPER_IMPL
#include "wrapper.h"

int wrapperFunc1 (...) {
   printf("Wrapper1 called\n");
   origFunc1(...);
}

Your wrapper's C file obviously needs to #define WRAPPER_IMPL before including the header.

That is neither nice nor clean (and if someone wants to cheat, he could simply define WRAPPER_IMPL), but at least some way to go.

Upvotes: 1

John Bollinger
John Bollinger

Reputation: 180898

You have several options, none of them wonderful.

  • if you have the sources of the legacy software, so that you can recompile it, you can just change the names of the API functions to make room for the wrapper functions. If you additionally make the original functions static and put the wrappers in the same source files, then you can ensure that the originals are called only via the wrappers. Example:
static int api_func_real(int arg);

int api_func(int arg) {
    // ... instrumentation ...
    int result = api_func_real(arg);
    // ... instrumentation ...
    return result;
}

static int api_func_real(int arg) {
    // ...
}

The preprocessor can help you with that, but I hesitate to recommend specifics without any details to work with.

  • if you do not have sources for the legacy software, or if otherwise you are unwilling to modify it, then you need to make all the callers call your wrappers instead of the original functions. In this case you can modify the headers or include an additional header before that uses #define to change each of the original function names. That header must not be included in the source files containing the API function implementations, nor in those providing the wrapper function implementations. Each define would be of the form:
#define api_func api_func_wrapper

You would then implement the various api_func_wrapper() functions.

Among the ways those cases differ is that if you change the legacy function names, then internal calls among those functions will go through the wrappers bearing the original names (unless you change the calls, too), but if you implement wrappers with new names then they will be used only when called explicitly, which will not happen for internal calls within the legacy code (unless, again, you modify those calls).

Upvotes: 1

Related Questions