Re: Use (f)puts instead of (f)printf when possible.

Bruno Haible <[email protected]>
Newsgroups gmane.lisp.clisp.devel
Message-ID <1731517.meCENGyaJR@omega>
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


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
clisp-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/clisp-devel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.