Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I ensure no code uses an API?

Tags:

c++

I want to ban use of iostreams in a code base I have (for various reasons). Is there a way I can inspect symbol files or force the compiler to emit an error when that API is used?

like image 247
Billy ONeal Avatar asked Aug 12 '13 01:08

Billy ONeal


3 Answers

This is a nasty hack, but it should work.

The C standard (and consequently the C++ standard as well) allows preprocessor tokens in #include directives. This is also known as "computed includes".

Thus, adding something like -Diostream to CFLAGS inside your makefile (or to compiler options in your IDE's project settings) should reliably break the build if someone tries to use iostream.

Of course, with an empty macro, the error message will not be very informative, but you could instead use something like -Diostream=DUDE_DONT_USE_IOSTREAM, which will show an error like: DUDE_DONT_USE_IOSTREAM: file not found.

It's also something that you can turn off again without much hassle if you change your mind later. Just remove the build option.

like image 45
Damon Avatar answered Oct 17 '22 02:10

Damon


A simple approach is provide a dummy iostream implementation that does nothing but throw a compile-time error.

The following example assumes a GCC toolchain - I imagine the process is similar with other compilers.

First, create your dummy iostream file:

#error 'Use of iostream is prohibited'

Some dummy application code to demonstrate:

#include <iostream>

int main (int argc, char** argv) {
    std::cout << "foo!";
    return 0;
}

Compile as follows (assuming the dummy iostream and main.cpp are in the working directory):

g++ -I. main.cpp

Compilation fails with the following errors:

In file included from main.cpp:2:0:
./iostream:1:2: error: #error 'Use of iostream is prohibited'
main.cpp: In function 'int main(int, char**)':
main.cpp:4:2: error: 'cout' is not a member of 'std'

Added bonus: symbols usually declared in that file (e.g. cout here) are undefined, and so get flagged in the compiler output as well. As such, you also get pointers to exactly where you're using your prohibited API.

UPDATE: Instructions for Visual C++ 2012.

As @RaymondChen points out in the comments below, a solution tailored to Visual C++ is likely more useful to the OP. As such, the following outlines the process I went through to achieve the same as the above under Visual C++ 2012.

First, create a new console project, using the above C++ code. Also create the dummy iostream header I described above, and place it in a directory somewhere easy to find (I put mine in the main project source directory).

Now, in the Solution Explorer, right click on the project node and select "Properties" from the drop-down list. In the dialog that appears, select "VC++ Directories" from the tree on the left. Prepend the directory containing the dummy iostream file into the list of include directories that appears on the right, separated from the other directories with a semicolon:

Adding new path to include directories list

Here, my project was called TestApp1, and I just prepended its main directory to the $(IncludePath) that was already there. Note that it is important to prepend rather than append - the order of the directories in the list determines the search order, so if $(IncludePath) appears before your custom directory, the system header will be used in preference to your dummy header - not what you want.

Click OK, and rebuild the project.

For me, doing so resulted in the following errors in the VC++ console (edited slightly for brevity):

error C1189: #error :  'Use of iostream is prohibited'
IntelliSense: #error directive: 'Use of iostream is prohibited'
IntelliSense: namespace "std" has no member "cout"

Note that IntelliSense also picks up the (now) illegal use of cout - it is highlighted with an error mark in the editor.

like image 149
Mac Avatar answered Oct 17 '22 02:10

Mac


Your idea to inspect symbol files is feasible and very realistic. virtual ~ios_base(); is a single method that all streams will inherit, and which can't easily be inlined since it's virtual and non-trivial. Its presence in an object file is therefore a very strong indication of IOstream use.

like image 28
MSalters Avatar answered Oct 17 '22 04:10

MSalters