On Tue, Feb 26, 2019 at 02:26:12PM +0000, Jonathan Wakely wrote: > On Mon, 25 Feb 2019 at 23:32, Segher Boessenkool > <segher@xxxxxxxxxxxxxxxxxxx> wrote: > > On Mon, Feb 25, 2019 at 11:18:31AM -0800, Jon Flatley wrote: > > > I was hoping I could reach out and gain some insight as to why GCC > > > ignores these scenarios where Clang produces warnings. This would be > > > very helpful as we move to enable -Wformat for both GCC and Clang in > > > the upstream kernel, which is an issue we're tracking here: > > > https://github.com/ClangBuiltLinux/linux/issues/378 > > > > You cannot pass a short int to a varargs function like printf, it is > > always promoted to int. As the C standard says for the h flag character: > > > > h > > Specifies that a following d, i, o, u, x, or X conversion specifier > > applies to a short int or unsigned short int argument (the argument > > will have been promoted according to the integer promotions, but > > its value shall be converted to short int or unsigned short int > > before printing); or that a following n conversion specifier applies > > to a pointer to a short int argument. > > A bit later it says: > > If any argument is > not the correct type for the corresponding conversion specification, > the behavior is > undefined. > > The "conversion specification" is %hd so includes both the h length > modifier and the d conversion specifier, and it's not clear to me > whether "the correct type" means the type as modified by the length > modifier or not, i.e. whether %hd It means "int" here, afaics. This is about whether the same types args are passed to the printf function as it is trying to read. > > Assuming the integer started out as short int before passing it to the > > printf function is something GCC does not do; > > But GCC doesn't need to assume anything when it can see exactly what's > being passed to printf. It can see that an int really is used there, > not just something promoted to int. Maybe I didn't say it clearly, sorry. If GCC wants to warn about passing a plain int to %hd it needs to assume this is "bad" somehow (even although the C standard says exactly how this should behave). > > it will warn on a lot of > > perfectly valid code. > > But also misses warnings for code with unintended (maybe even > undefined) behaviour: > > #include <stdio.h> > #include <limits.h> > > int main() > { > int i = SHRT_MAX + 1; > printf("%hd %hd\n", i, SHRT_MAX + 1); > } Conversion to a shorter integer type can be implementation-defined, not undefined. GCC has For conversion to a type of width N, the value is reduced modulo 2^N to be within range of the type; no signal is raised. (but it is a bit shady what printf does exactly, it's not part of GCC; but we can probably assume it is compiled by GCC itself). > Inside printf the int values are converted to short, which is either > an overflow (so undefined) or, if the conversion is done via unsigned > types, at least a change in value that is probably unwanted. It's implementation-defined, see 6.3.1.3/3. > The compiler should be able to warn that SHRT_MAX+1 will not be > printed correctly. That depends what you call "correct". As I said, there will be lots of false positives with such a warning, as OP already showed. Segher