Avinash
Avinash

Reputation: 13257

compiler way to stop using certain C system calls

I want people to stop using functions like sprintf as it is considered an unsafe function. Is there a compiler way to give compilation error if sprintf is used in the code, or any other trick?

Upvotes: 3

Views: 302

Answers (4)

ArjunShankar
ArjunShankar

Reputation: 23680

GCC supports this sort of thing with #pragma GCC poison. Using this pragma followed by a list of identifiers will cause the use of any of the identifiers in the program to throw an error. For example, this program won't compile:

#include <stdio.h>

#pragma GCC poison fprintf sprintf

int main (void)
{
  char foo[100];
  sprintf (foo, "bar");
  return 0;
}

If a macro defined before the pragma expands to the identifier, then that occurance won't be poisoned. For example, this program will compile:

#include <stdio.h>

#define print_to_string sprintf
#pragma GCC poison sprintf

int main (void)
{
  char foo[100];
  print_to_string (foo, "bar");
  return 0;
}

Upvotes: 8

ouah
ouah

Reputation: 145829

Other people have mentioned triggering a compilation error.

Unfortunately the error message is often not very explicit if you want to differentiate the errors. A good thing to do is to have an undefined object with a name that embeds the error message, like this:

#define sprintf (do_not_use_sprintf_call = 0) 

So when sprintf is called the gcc error message will be more explicit:

tst.c: In function `main':
tst.c:11: error: `do_not_use_sprintf_call' undeclared (first use in
this function)
tst.c:11: error: (Each undeclared identifier is reported only once
tst.c:11: error: for each function it appears in.)

Note that with C11 you can also have your own error message using a static assert:

#define sprintf _Static_assert(0, "do_not_use_sprintf_call")

Upvotes: 3

Mawg
Mawg

Reputation: 40140

Not an answer, but I am too dumb to know how to post formatted code in a reply.

IMO, @myrkos has given the correct answer to this question.

However, he speaks of a compile time error, and I also like to generalize out to a compile time assert (aka static assert).

Google those terms and you will get a bunch of suggestions. Depending on your compiler, some will give more pleasing error messages than others, so make a small test program. I personally (ymmv) prefer this one with GCC (apologies to the original author as I can't remember where I "borrowed" it from - it was so long ago and it still serves me well):

/** A "static assert", which checks a condition at compile time, rather  
 * than run time. The sooner problems are found, the sooner they can be fixed
 * (and with less effort).
 *
 * Use this one where you don't even want the code to begin running
 * if something is wrong. If you don't use this, you need a test case,
 * but sometimes tests don't get run, so use this for the sort of thing
 * that should never be released to the customer (or even the test department).
 *
 * Example: ASSERT_AT_COMPILE_TIME(1==2), one_does_not_equal_two);
 *          gives this error message under GNU on Linux:
 *             size of array one_does_not_equal_two is negative
 *
 * Note: this is very useful checking the size of user defined types, like uint64_t
 * or for doing things like this:
 *
 * struct foo {
 *       int x;
 *       int y;
 * };
 * ASSERT_AT_COMPILE_TIME(offsetof(struct foo, y) == 4, y_is_at_offset_4);
 */
#define ASSERT_CAT1(x) ASSERT_CAT ## x
#define ASSERT_CAT0(x) ASSERT_CAT1(x)
#define ASSERT_AT_COMPILE_TIME(expression, message)  \
         struct ASSERT_CAT0(__LINE__) {char message[2*!!(expression)-1]; }

Upvotes: 0

slartibartfast
slartibartfast

Reputation: 4428

#define sprintf COMPILE_TIME_ERROR
#define COMPILE_TIME_ERROR switch(0){case 0:case 0:;}

int main(void) {
 char hi[50];
 sprintf(hi,"hi");
 return 0;
}

Compiler output will be something like:

prog.c: In function ‘main’:
prog.c:6: error: duplicate case value
prog.c:6: error: previously used here

Upvotes: 5

Related Questions