Reputation: 13257
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
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
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
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
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