From: Bruno H. <br...@cl...> - 2017-08-24 21:11:42
|
Hi Sam, > Use (f)puts instead of (f)printf when possible. I guess this was motivated by Jerry's remark: ! Fedora builds with -Werror=format-security, so I had to change ! one line in the aarch64 patch. That patch modifies spvw_allocate.d ! and in one place issues a warning. I had to change this line: ! ! fprintf(stderr, GETTEXTL("Warning: ")); ! ! to: ! ! fputs(GETTEXTL("Warning: "),stderr); ! ! since the string is non-constant, and therefore triggers the format ! security error. Two things about this: 1) There is an (undocumented) way to avoid this security warning. Test case: =============================================================================== #include <stdio.h> extern const char * transform1 (const char * s); extern const char * transform2 (const char * s) __attribute__ ((__format_arg__ (1))); void foo1 () { fprintf(stderr, transform1("Hello")); } void foo2 () { fprintf(stderr, transform2("Hello")); } =============================================================================== $ gcc -S -Wall -Wformat-security foo.c foo.c: In function 'foo1': foo.c:4:1: warning: format not a string literal and no format arguments [-Wformat-security] void foo1 () { fprintf(stderr, transform1("Hello")); } ^~~~ As you can see, this __attribute__ ((__format_arg__ (1))) has the effect of avoiding the warning. But since it is undocumented, I agree to avoid fprintf with format-strings that take 0 arguments, and use literal strings instead. Even though it will likely cause work for the translators. 2) I dislike APIs that are hard to remember. * fputs, fputc, putc have the problem that it requires you do put the stream after the arguments, which is unlike fprintf, object_out, etc. * puts additionally emits an extra newline. Really, when writing a sequence of outputs to the same stream, these inconsistencies lead to mistakes: extra or missing newlines at the end of an output. If we were using <stdio.h> only in 1 or 2 places, this would be acceptable. But we're using it all over the place. Additionally, there is no need to optimize fputs("x",stdout) to fputc('x',stdout) because the compiler (gcc) does this optimization already for years. Therefore I've introduced two macros /* Use fprintf and printf only for format strings that take at least 1 argument. For literal strings, use print and fprint. Avoid using fputs, puts, fputc, putc, putchar directly, because these APIs are hard to memorize (fputs, fputc, putc don't take the stream first; puts outputs an extra newline) or redundant (fputc, putc, putchar are special cases of fputs that GCC recognizes anyway). */ #define fprint(fp,string) fputs(string,fp) #define print(string) fputs(string,stdout) The code looks now more consistent, since there are now exactly 4 primitives: fprintf printf fprint print and they have the signature that you expect. Bruno |