[cfe-dev] Tool for easy test seam injection in legacy C code

Manuel Klimek klimek at google.com
Sun Dec 21 08:24:51 PST 2014


On Sat Dec 20 2014 at 12:26:08 PM Ivan Koster <ivankoster at gmail.com> wrote:

> Hello all,
>
> I want to create a tool that facilitates easy test seam injection in
> legacy C code.
> The reason for this is many colleagues (including myself) finding it very
> tedious and maintenance intensive to create stubs / mocks for our legacy C
> code base. This causes us to write less unittests than we want to. We
> currently use a routing mechanism with #defines in a .h file that reroutes
> functions to stubs/mocks and is included when we compile for unittesting.
>
> I have been researching several ways of creating test seams, and have
> settled on a method which leverages function pointers. A welcome help was
> the article at
> http://meekrosoft.wordpress.com/2012/07/20/test-seams-in-c-function-pointers-vs-preprocessor-hash-defines-vs-link-time-substitution/
> But to make it truly easy, I need the compiler to do it for me. This is
> were clang/llvm comes in.
>
> What I want is the following. Given the following 2 files:
>
> // interface.h
> __attribute__((easy_test_seam))
> int foo(void);
>
> // implementation.c
> int foo(void)
> {
>     return 2;
> }
>
>
> I actually want it to be compiled as:
>
> // interface.h
> extern int (*foo)(void);
>
> // implementation.c
> int foo_orig(void)
> {
>     return 2;
> }
> int (*foo)(void) = foo_orig;
>
>
> In a later stage we could also add standard stub generation, maybe an
> attribute like:
>
> __attribute__((easy_test_seam(5)))
> int foo(void);
>
> Which would also create a standard stub that returns 5;
>
> I see this method as a huge relief. It's maintenance friendly, we only
> have to add the attribute to the legacy interfaces. We will only act on the
> attribute if we compile for unittesting. Since we then won't have changed
> production code it also won't mess up static analysis of production code
> and won't fool IDE's jump to definition functionality.
>
> The last few days I have been researching how to do this.
>
> I have seen many suggest source-to-source transformation using the clang
> Rewriter class. This is not my preferred choice, I don't have the need to
> edit the *.c and *.h files, I just want them compiled differently. I would
> also have to extend our build system to clone my *.c and *.h files, run
> them through the source-to-source transform tool, and then compile the
> resulting .c and .h files. This is not insurmountable, but not trivial
> either.
>

It is pretty much the same as editing the AST directly. You can do all the
source editing in memory in a single tool, *and* do the compile step on the
changed source from the same tool; no need to write anything to disk (in
fact, the rewriting tools all have the source in memory before they edit
the files on disk).


>
> I've seen some suggestions against changing the clang AST, because it's
> supposed to be immutable and is hard.
>
> I've also seen some suggestions to do LLVM IR transform passes, but I
> haven't dived deep enough in LLVM IR to determine if this can work or not.
>
> I'm very new to clang and LLVM, can you guys help me determine which of
> the three ways would be the way to go? Or maybe there is another way?
>
> Thanks in advance!
>
> Regards,
>
> Ivan
>
>
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20141221/fd8797cc/attachment.html>


More information about the cfe-dev mailing list