Re: Inconsistent printf format warnings for macro in system headers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 10/16/2015 08:40 AM, Olivier Blin wrote:
Hello,

In gcc versions starting from 4.8, it seems that printf format warnings
in macros are inconsistent, depending on whether the header defining the
macro is included as a system header or not, and on the build mode (C or
C++).

With gcc < 4.8 (tried gcc 4.6.3 and 4.7.2), there are printf format
warnings for both C and C++ languages, when the macro is in a system
header or not.

With gcc >= 4.8 (tried 4.8.2 and 5.2.1 snapshot), there are no printf
format warnings when the build mode is C++ *and* when the macro is in a
system header.
If the build mode is C or if the macro is in a non-system header, the
printf format warnings are emitted.

Please see below for a test case and results in various configurations.
Can this be considered as a bug in gcc ?
Or is this behavior somehow expected?
If so, what is the proper way to get printf format warnings in C++ mode
for macros defined in system headers?

I'm inclined to say it's a bug. I recommend opening it in Bugzilla.
The only way I was able to work around it is by changing MY_PRINTF
from a function-like macro to an object macro like so:

  #define MY_PRINTF printf

The problem isn't specific to -Wformat but can be reproduced with
other warnings as well. For example, replacing the contents of
the header in the test case with this:

  #pragma GCC system_header

  static inline void __attribute__ ((deprecated)) foobar (void) { }

  #define foo foobar
  #define bar() foobar()

and the body of main with

  foo ();
  bar ();

emits a warning for each of foo() and bar() in C but just one,
for foo(), in C++.

While stepping through the code that checks to see whether or not
a diagnostic should be issued (diagnostic_issue_diagnostic) I see
that the difference in the bar() case is in the return value of
the linemap_macro_expansion_map_p() function which is documented
to

  Return TRUE if MAP encodes locations coming from a macro
  replacement-list at macro expansion point.

and implemented by testing the location MAP's REASON member for
equality to the LC_ENTER_MACRO constant. In C, the REASON member
is set to LC_LEAVE while in C++ to LC_ENTER_MACRO. In C, the
call to bar is then treated as an ordinary token whose location
(i.e., bar's invocation) determines whether or not to issue the
diagnostic. In C++ the reference to bar is recognized as a macro
expansion and the function proceeds to find the token it expands
to and use that to determine whether or not to diagnose it. And
since the token bar() expands to is defined in a system header,
C++ doesn't issue the warning.

In the case of foo(), the REASON is LC_LEAVE in both front-ends
and so they both diagnose it.

Martin


Thanks in advance


Here is a sample test case:
$ mkdir -p syshdr_dir
$ cat <<EOF > syshdr_dir/myprintf.h
#include <stdio.h>
#define MY_PRINTF(x, ...) printf(x, ## __VA_ARGS__);
EOF

$ cat <<EOF > test-format-printf.c
#include <myprintf.h>
int main(void) {
     long long ll = 0;
     MY_PRINTF("%ld", ll);
     return 0;
}
EOF

With gcc 4.6.3 and 4.7.2, I get printf format warnings for both C and
C++ languages.

$ gcc -isystem $PWD/syshdr_dir -Wall -Werror -x c++ -c
test-format-printf.c -o /dev/null
test-format-printf.c: In function ‘int main()’:
test-format-printf.c:4:5: error: format ‘%ld’ expects argument of type
‘long int’, but argument 2 has type ‘long long int’ [-Werror=format]
cc1plus: all warnings being treated as errors

$ gcc -isystem $PWD/syshdr_dir -Wall -Werror -x c -c
test-format-printf.c -o /dev/null
test-format-printf.c: In function ‘main’:
test-format-printf.c:4:5: error: format ‘%ld’ expects argument of type
‘long int’, but argument 2 has type ‘long long int’ [-Werror=format]
cc1: all warnings being treated as errors


With gcc 4.8.2 and a 5.2.1 snapshot, there is a warning for C, but no
warning for C++ when the macro is in a system header.

$ gcc -isystem $PWD/syshdr_dir -Wall -Werror -x c++ -c
test-format-printf.c -o /dev/null

$ gcc -isystem $PWD/syshdr_dir -Wall -Werror -x c -c
test-format-printf.c -o /dev/null
In file included from test-format-printf.c:1:0:
test-format-printf.c: In function ‘main’:
test-format-printf.c:4:15: error: format ‘%ld’ expects argument of type
‘long int’, but argument 2 has type ‘long long int’ [-Werror=format=]
      MY_PRINTF("%ld", ll);
                ^
cc1: all warnings being treated as errors

$ gcc -I $PWD/syshdr_dir -Wall -Werror -x c++ -c test-format-printf.c -o
/dev/null
In file included from test-format-printf.c:1:0:
test-format-printf.c: In function ‘int main()’:
/home/sah0146/dev/workspaces/bcm7252/hgw/build/MAIN/syshdr_dir/myprintf.h:2:51:
error: format ‘%ld’ expects argument of type ‘long int’, but argument 2
has type ‘long long int’ [-Werror=format=]
  #define MY_PRINTF(x, ...) printf(x, ## __VA_ARGS__);
                                                    ^
test-format-printf.c:4:5: note: in expansion of macro ‘MY_PRINTF’
      MY_PRINTF("%ld", ll);
      ^
cc1plus: all warnings being treated as errors





[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux