2021-10-27 15:38:31 -07:00
// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs %s
// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs -fno-signed-char %s
2022-01-21 21:00:39 +00:00
// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs -triple=x86_64-unknown-fuchsia %s
// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs -triple=x86_64-linux-android %s
2007-08-10 20:18:51 +00:00
# include <stdarg.h>
2014-04-30 04:35:09 +00:00
# include <stddef.h>
# define __need_wint_t
2012-05-04 10:55:22 +00:00
# include <stddef.h> // For wint_t and wchar_t
2009-11-17 08:57:36 +00:00
typedef struct _FILE FILE ;
int fprintf ( FILE * , const char * restrict , . . . ) ;
2010-04-22 00:20:18 +00:00
int printf ( const char * restrict , . . . ) ; // expected-note{{passing argument to parameter here}}
2009-11-17 08:57:36 +00:00
int snprintf ( char * restrict , size_t , const char * restrict , . . . ) ;
int sprintf ( char * restrict , const char * restrict , . . . ) ;
int vasprintf ( char * * , const char * , va_list ) ;
2010-01-09 20:43:19 +00:00
int asprintf ( char * * , const char * , . . . ) ;
2009-11-17 08:57:36 +00:00
int vfprintf ( FILE * , const char * restrict , va_list ) ;
int vprintf ( const char * restrict , va_list ) ;
int vsnprintf ( char * , size_t , const char * , va_list ) ;
2010-04-22 00:20:18 +00:00
int vsprintf ( char * restrict , const char * restrict , va_list ) ; // expected-note{{passing argument to parameter here}}
2007-08-10 20:18:51 +00:00
2012-02-21 20:00:53 +00:00
int vscanf ( const char * restrict format , va_list arg ) ;
2007-12-17 19:03:13 +00:00
char * global_fmt ;
2007-08-10 20:18:51 +00:00
void check_string_literal ( FILE * fp , const char * s , char * buf , . . . ) {
char * b ;
va_list ap ;
va_start ( ap , buf ) ;
printf ( s ) ; // expected-warning {{format string is not a string literal}}
2016-03-15 20:56:38 +00:00
// expected-note@-1{{treat the string as an argument to avoid this}}
2012-02-21 20:00:53 +00:00
vprintf ( s , ap ) ; // expected-warning {{format string is not a string literal}}
2007-08-10 20:18:51 +00:00
fprintf ( fp , s ) ; // expected-warning {{format string is not a string literal}}
2016-03-15 20:56:38 +00:00
// expected-note@-1{{treat the string as an argument to avoid this}}
2012-02-21 20:00:53 +00:00
vfprintf ( fp , s , ap ) ; // expected-warning {{format string is not a string literal}}
2007-08-10 20:18:51 +00:00
asprintf ( & b , s ) ; // expected-warning {{format string is not a string lit}}
2016-03-15 20:56:38 +00:00
// expected-note@-1{{treat the string as an argument to avoid this}}
2012-02-21 20:00:53 +00:00
vasprintf ( & b , s , ap ) ; // expected-warning {{format string is not a string literal}}
2007-08-10 20:18:51 +00:00
sprintf ( buf , s ) ; // expected-warning {{format string is not a string literal}}
2016-03-15 20:56:38 +00:00
// expected-note@-1{{treat the string as an argument to avoid this}}
2007-08-10 20:18:51 +00:00
snprintf ( buf , 2 , s ) ; // expected-warning {{format string is not a string lit}}
2016-03-15 20:56:38 +00:00
// expected-note@-1{{treat the string as an argument to avoid this}}
2008-10-02 18:44:07 +00:00
__builtin___sprintf_chk ( buf , 0 , - 1 , s ) ; // expected-warning {{format string is not a string literal}}
2016-03-15 20:56:38 +00:00
// expected-note@-1{{treat the string as an argument to avoid this}}
2008-10-02 18:44:07 +00:00
__builtin___snprintf_chk ( buf , 2 , 0 , - 1 , s ) ; // expected-warning {{format string is not a string lit}}
2016-03-15 20:56:38 +00:00
// expected-note@-1{{treat the string as an argument to avoid this}}
2012-02-21 20:00:53 +00:00
vsprintf ( buf , s , ap ) ; // expected-warning {{format string is not a string lit}}
vsnprintf ( buf , 2 , s , ap ) ; // expected-warning {{format string is not a string lit}}
2007-12-17 19:03:13 +00:00
vsnprintf ( buf , 2 , global_fmt , ap ) ; // expected-warning {{format string is not a string literal}}
2012-02-21 20:00:53 +00:00
__builtin___vsnprintf_chk ( buf , 2 , 0 , - 1 , s , ap ) ; // expected-warning {{format string is not a string lit}}
2008-10-02 18:44:07 +00:00
__builtin___vsnprintf_chk ( buf , 2 , 0 , - 1 , global_fmt , ap ) ; // expected-warning {{format string is not a string literal}}
2009-02-18 18:25:31 +00:00
2012-02-21 20:00:53 +00:00
vscanf ( s , ap ) ; // expected-warning {{format string is not a string literal}}
2016-02-26 15:35:16 +00:00
const char * const fmt = " %d " ; // FIXME -- defined here
printf ( fmt , 1 , 2 ) ; // expected-warning{{data argument not used}}
2009-02-18 18:34:12 +00:00
printf ( " abc "
2010-01-29 23:32:22 +00:00
" %*d " , 1 , 1 ) ; // no-warning
2009-02-18 18:34:12 +00:00
printf ( " abc \
def "
2010-01-29 23:32:22 +00:00
" %*d " , 1 , 1 ) ; // no-warning
2022-07-22 15:24:54 -04:00
[clang] Remove rdar links; NFC
We have a new policy in place making links to private resources
something we try to avoid in source and test files. Normally, we'd
organically switch to the new policy rather than make a sweeping change
across a project. However, Clang is in a somewhat special circumstance
currently: recently, I've had several new contributors run into rdar
links around test code which their patch was changing the behavior of.
This turns out to be a surprisingly bad experience, especially for
newer folks, for a handful of reasons: not understanding what the link
is and feeling intimidated by it, wondering whether their changes are
actually breaking something important to a downstream in some way,
having to hunt down strangers not involved with the patch to impose on
them for help, accidental pressure from asking for potentially private
IP to be made public, etc. Because folks run into these links entirely
by chance (through fixing bugs or working on new features), there's not
really a set of problematic links to focus on -- all of the links have
basically the same potential for causing these problems. As a result,
this is an omnibus patch to remove all such links.
This was not a mechanical change; it was done by manually searching for
rdar, radar, radr, and other variants to find all the various
problematic links. From there, I tried to retain or reword the
surrounding comments so that we would lose as little context as
possible. However, because most links were just a plain link with no
supporting context, the majority of the changes are simple removals.
Differential Review: https://reviews.llvm.org/D158071
2023-08-28 12:13:42 -04:00
// Allow 'unsigned' (instead of 'int') to be used for both the field width
// and precision. This deviates from C99, but is reasonably safe and is also
// accepted by GCC.
2022-07-22 15:24:54 -04:00
printf ( " %*d " , ( unsigned ) 1 , 1 ) ; // no-warning
2007-08-10 20:18:51 +00:00
}
2013-01-12 22:39:30 +00:00
// When calling a non-variadic format function (vprintf, vscanf, NSLogv, ...),
// warn only if the format string argument is a parameter that is not itself
// declared as a format string with compatible format.
2012-02-21 20:00:53 +00:00
__attribute__ ( ( __format__ ( __printf__ , 2 , 4 ) ) )
void check_string_literal2 ( FILE * fp , const char * s , char * buf , . . . ) {
char * b ;
va_list ap ;
va_start ( ap , buf ) ;
printf ( s ) ; // expected-warning {{format string is not a string literal}}
2016-03-15 20:56:38 +00:00
// expected-note@-1{{treat the string as an argument to avoid this}}
2012-02-21 20:00:53 +00:00
vprintf ( s , ap ) ; // no-warning
fprintf ( fp , s ) ; // expected-warning {{format string is not a string literal}}
2016-03-15 20:56:38 +00:00
// expected-note@-1{{treat the string as an argument to avoid this}}
2012-02-21 20:00:53 +00:00
vfprintf ( fp , s , ap ) ; // no-warning
asprintf ( & b , s ) ; // expected-warning {{format string is not a string lit}}
2016-03-15 20:56:38 +00:00
// expected-note@-1{{treat the string as an argument to avoid this}}
2012-02-21 20:00:53 +00:00
vasprintf ( & b , s , ap ) ; // no-warning
sprintf ( buf , s ) ; // expected-warning {{format string is not a string literal}}
2016-03-15 20:56:38 +00:00
// expected-note@-1{{treat the string as an argument to avoid this}}
2012-02-21 20:00:53 +00:00
snprintf ( buf , 2 , s ) ; // expected-warning {{format string is not a string lit}}
2016-03-15 20:56:38 +00:00
// expected-note@-1{{treat the string as an argument to avoid this}}
2012-02-21 20:00:53 +00:00
__builtin___vsnprintf_chk ( buf , 2 , 0 , - 1 , s , ap ) ; // no-warning
2025-02-24 18:58:59 -08:00
vscanf ( s , ap ) ; // expected-warning {{passing 'printf' format string where 'scanf' format string is expected}}
2012-02-21 20:00:53 +00:00
}
2009-01-12 23:09:09 +00:00
void check_conditional_literal ( const char * s , int i ) {
printf ( i = = 1 ? " yes " : " no " ) ; // no-warning
printf ( i = = 0 ? ( i = = 1 ? " yes " : " no " ) : " dont know " ) ; // no-warning
2009-01-12 23:09:55 +00:00
printf ( i = = 0 ? ( i = = 1 ? s : " no " ) : " dont know " ) ; // expected-warning{{format string is not a string literal}}
2016-03-15 20:56:38 +00:00
// expected-note@-1{{treat the string as an argument to avoid this}}
2010-02-26 19:18:41 +00:00
printf ( " yes " ? : " no %d " , 1 ) ; // expected-warning{{data argument not used by format string}}
2016-02-26 15:35:16 +00:00
printf ( 0 ? " yes %s " : " no %d " , 1 ) ; // no-warning
printf ( 0 ? " yes %d " : " no %s " , 1 ) ; // expected-warning{{format specifies type 'char *'}}
printf ( 0 ? " yes " : " no %d " , 1 ) ; // no-warning
printf ( 0 ? " yes %d " : " no " , 1 ) ; // expected-warning{{data argument not used by format string}}
printf ( 1 ? " yes " : " no %d " , 1 ) ; // expected-warning{{data argument not used by format string}}
printf ( 1 ? " yes %d " : " no " , 1 ) ; // no-warning
printf ( i ? " yes " : " no %d " , 1 ) ; // no-warning
printf ( i ? " yes %s " : " no %d " , 1 ) ; // expected-warning{{format specifies type 'char *'}}
printf ( i ? " yes " : " no %d " , 1 , 2 ) ; // expected-warning{{data argument not used by format string}}
printf ( i ? " %*s " : " - " , i , s ) ; // no-warning
printf ( i ? " yes " : 0 ? " no %*d " : " dont know %d " , 1 , 2 ) ; // expected-warning{{data argument not used by format string}}
printf ( i ? " %i \n " : " %i %s %s \n " , i , s ) ; // expected-warning{{more '%' conversions than data arguments}}
2009-01-12 23:09:09 +00:00
}
2022-01-21 21:00:39 +00:00
# if !defined(__ANDROID__) && !defined(__Fuchsia__)
2022-02-04 15:19:56 -05:00
void check_writeback_specifier ( void )
2007-08-14 17:39:48 +00:00
{
int x ;
char * b ;
2012-07-30 20:21:58 +00:00
printf ( " %n " , b ) ; // expected-warning{{format specifies type 'int *' but the argument has type 'char *'}}
printf ( " %n " , & x ) ; // no-warning
2012-08-07 09:13:19 +00:00
printf ( " %hhn " , ( signed char * ) 0 ) ; // no-warning
printf ( " %hhn " , ( char * ) 0 ) ; // no-warning
printf ( " %hhn " , ( unsigned char * ) 0 ) ; // no-warning
printf ( " %hhn " , ( int * ) 0 ) ; // expected-warning{{format specifies type 'signed char *' but the argument has type 'int *'}}
printf ( " %hn " , ( short * ) 0 ) ; // no-warning
printf ( " %hn " , ( unsigned short * ) 0 ) ; // no-warning
printf ( " %hn " , ( int * ) 0 ) ; // expected-warning{{format specifies type 'short *' but the argument has type 'int *'}}
printf ( " %n " , ( int * ) 0 ) ; // no-warning
printf ( " %n " , ( unsigned int * ) 0 ) ; // no-warning
printf ( " %n " , ( char * ) 0 ) ; // expected-warning{{format specifies type 'int *' but the argument has type 'char *'}}
printf ( " %ln " , ( long * ) 0 ) ; // no-warning
printf ( " %ln " , ( unsigned long * ) 0 ) ; // no-warning
printf ( " %ln " , ( int * ) 0 ) ; // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}
printf ( " %lln " , ( long long * ) 0 ) ; // no-warning
printf ( " %lln " , ( unsigned long long * ) 0 ) ; // no-warning
printf ( " %lln " , ( int * ) 0 ) ; // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}}
printf ( " %qn " , ( long long * ) 0 ) ; // no-warning
printf ( " %qn " , ( unsigned long long * ) 0 ) ; // no-warning
printf ( " %qn " , ( int * ) 0 ) ; // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}}
printf ( " %Ln " , 0 ) ; // expected-warning{{length modifier 'L' results in undefined behavior or no effect with 'n' conversion specifier}}
2012-09-08 04:00:12 +00:00
// expected-note@-1{{did you mean to use 'll'?}}
2007-08-14 17:39:48 +00:00
}
2022-01-21 21:00:39 +00:00
# else
2022-02-04 15:19:56 -05:00
void check_writeback_specifier ( void )
2022-01-21 21:00:39 +00:00
{
int x ;
printf ( " %n " , & x ) ; // expected-warning{{'%n' specifier not supported on this platform}}
printf ( " %hhn " , ( signed char * ) 0 ) ; // expected-warning{{'%n' specifier not supported on this platform}}
printf ( " %hhn " , ( char * ) 0 ) ; // expected-warning{{'%n' specifier not supported on this platform}}
printf ( " %hhn " , ( unsigned char * ) 0 ) ; // expected-warning{{'%n' specifier not supported on this platform}}
printf ( " %hhn " , ( int * ) 0 ) ; // expected-warning{{format specifies type 'signed char *' but the argument has type 'int *'}}
// expected-warning@-1 {{'%n' specifier not supported on this platform}}
printf ( " %hn " , ( short * ) 0 ) ; // expected-warning{{'%n' specifier not supported on this platform}}
printf ( " %hn " , ( unsigned short * ) 0 ) ; // expected-warning{{'%n' specifier not supported on this platform}}
printf ( " %hn " , ( int * ) 0 ) ; // expected-warning{{format specifies type 'short *' but the argument has type 'int *'}}
// expected-warning@-1 {{'%n' specifier not supported on this platform}}
printf ( " %n " , ( int * ) 0 ) ; // expected-warning{{'%n' specifier not supported on this platform}}
printf ( " %n " , ( unsigned int * ) 0 ) ; // expected-warning{{'%n' specifier not supported on this platform}}
printf ( " %n " , ( char * ) 0 ) ; // expected-warning{{format specifies type 'int *' but the argument has type 'char *'}}
// expected-warning@-1 {{'%n' specifier not supported on this platform}}
printf ( " %ln " , ( long * ) 0 ) ; // expected-warning{{'%n' specifier not supported on this platform}}
printf ( " %ln " , ( unsigned long * ) 0 ) ; // expected-warning{{'%n' specifier not supported on this platform}}
printf ( " %ln " , ( int * ) 0 ) ; // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}
// expected-warning@-1 {{'%n' specifier not supported on this platform}}
printf ( " %lln " , ( long long * ) 0 ) ; // expected-warning{{'%n' specifier not supported on this platform}}
printf ( " %lln " , ( unsigned long long * ) 0 ) ; // expected-warning{{'%n' specifier not supported on this platform}}
printf ( " %lln " , ( int * ) 0 ) ; // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}}
// expected-warning@-1 {{'%n' specifier not supported on this platform}}
printf ( " %qn " , ( long long * ) 0 ) ; // expected-warning{{'%n' specifier not supported on this platform}}
printf ( " %qn " , ( unsigned long long * ) 0 ) ; // expected-warning{{'%n' specifier not supported on this platform}}
}
# endif // !defined(__ANDROID__) && !defined(__Fuchsia__)
2007-08-14 17:39:48 +00:00
void check_invalid_specifier ( FILE * fp , char * buf )
{
2022-08-04 10:26:31 -07:00
printf ( " %s%lv%d " , " unix " , 10 , 20 ) ; // expected-warning {{invalid conversion specifier 'v'}} expected-warning {{data argument not used by format string}}
2010-01-29 20:55:36 +00:00
fprintf ( fp , " %%%l " ) ; // expected-warning {{incomplete format specifier}}
2012-01-20 21:52:58 +00:00
sprintf ( buf , " %%%%%ld%d%d " , 1 , 2 , 3 ) ; // expected-warning{{format specifies type 'long' but the argument has type 'int'}}
2023-08-26 14:41:05 +09:00
snprintf ( buf , 2 , " %%%%%ld%;%d " , 1 , 2 , 3 ) ; / / expected - warning { { format specifies type ' long ' but the argument has type ' int ' } } expected - warning { { invalid conversion specifier ' ; ' } } expected - warning { { data argument not used by format string } } \
// expected-warning{{'snprintf' will always be truncated; specified size is 2, but format string expands to at least 7}}
2007-08-14 17:39:48 +00:00
}
void check_null_char_string ( char * b )
{
printf ( " \0 this is bogus%d " , 1 ) ; // expected-warning {{string contains '\0'}}
snprintf ( b , 10 , " %%%%%d \0 %d " , 1 , 2 ) ; // expected-warning {{string contains '\0'}}
printf ( " % \0 d " , 1 ) ; // expected-warning {{string contains '\0'}}
}
2007-10-12 17:48:41 +00:00
void check_empty_format_string ( char * buf , . . . )
2007-08-14 17:39:48 +00:00
{
va_list ap ;
va_start ( ap , buf ) ;
vprintf ( " " , ap ) ; // expected-warning {{format string is empty}}
2011-09-29 05:52:16 +00:00
sprintf ( buf , " " , 1 ) ; // expected-warning {{format string is empty}}
2022-07-22 15:24:54 -04:00
2011-09-29 05:52:16 +00:00
// Don't warn about empty format strings when there are no data arguments.
// This can arise from macro expansions and non-standard format string
// functions.
sprintf ( buf , " " ) ; // no-warning
2007-08-14 17:39:48 +00:00
}
2007-10-12 17:48:41 +00:00
void check_wide_string ( char * b , . . . )
2007-08-14 17:39:48 +00:00
{
va_list ap ;
va_start ( ap , b ) ;
2008-08-05 00:07:51 +00:00
printf ( L " foo %d " , 2 ) ; // expected-warning {{incompatible pointer types}}, expected-warning {{should not be a wide string}}
2009-10-29 00:10:42 +00:00
vsprintf ( b , L " bar %d " , ap ) ; // expected-warning {{incompatible pointer types}}, expected-warning {{should not be a wide string}}
2007-08-14 17:39:48 +00:00
}
2007-10-12 20:51:52 +00:00
void check_asterisk_precision_width ( int x ) {
printf ( " %*d " ) ; // expected-warning {{'*' specified field width is missing a matching 'int' argument}}
printf ( " %.*d " ) ; // expected-warning {{'.*' specified field precision is missing a matching 'int' argument}}
printf ( " %*d " , 12 , x ) ; // no-warning
printf ( " %*d " , " foo " , x ) ; // expected-warning {{field width should have type 'int', but argument has type 'char *'}}
printf ( " %.*d " , " foo " , x ) ; // expected-warning {{field precision should have type 'int', but argument has type 'char *'}}
2008-08-05 00:07:51 +00:00
}
2009-02-14 18:57:46 +00:00
void __attribute__ ( ( format ( printf , 1 , 3 ) ) ) myprintf ( const char * , int blah , . . . ) ;
2022-02-04 15:19:56 -05:00
void test_myprintf ( void ) {
2009-02-14 18:57:46 +00:00
myprintf ( " %d " , 17 , 18 ) ; // okay
}
2009-03-20 21:35:28 +00:00
void test_constant_bindings ( void ) {
const char * const s1 = " hello " ;
const char s2 [ ] = " hello " ;
const char * s3 = " hello " ;
char * const s4 = " hello " ;
extern const char s5 [ ] ;
2022-07-22 15:24:54 -04:00
2009-03-20 21:35:28 +00:00
printf ( s1 ) ; // no-warning
printf ( s2 ) ; // no-warning
printf ( s3 ) ; // expected-warning{{not a string literal}}
2016-03-15 20:56:38 +00:00
// expected-note@-1{{treat the string as an argument to avoid this}}
2009-03-20 21:35:28 +00:00
printf ( s4 ) ; // expected-warning{{not a string literal}}
2016-03-15 20:56:38 +00:00
// expected-note@-1{{treat the string as an argument to avoid this}}
2009-03-20 21:35:28 +00:00
printf ( s5 ) ; // expected-warning{{not a string literal}}
2016-03-15 20:56:38 +00:00
// expected-note@-1{{treat the string as an argument to avoid this}}
2009-03-20 21:35:28 +00:00
}
2009-04-29 04:59:47 +00:00
// Test what happens when -Wformat-security only.
# pragma GCC diagnostic ignored "-Wformat-nonliteral"
# pragma GCC diagnostic warning "-Wformat-security"
void test9 ( char * P ) {
int x ;
printf ( P ) ; // expected-warning {{format string is not a string literal (potentially insecure)}}
2016-03-15 20:56:38 +00:00
// expected-note@-1{{treat the string as an argument to avoid this}}
2009-04-29 04:59:47 +00:00
printf ( P , 42 ) ;
}
2009-05-13 16:06:05 +00:00
void torture ( va_list v8 ) {
vprintf ( " %*.*d " , v8 ) ; // no-warning
2022-07-22 15:24:54 -04:00
2009-05-13 16:06:05 +00:00
}
2010-01-30 15:49:20 +00:00
void test10 ( int x , float f , int i , long long lli ) {
2010-02-27 08:34:51 +00:00
printf ( " %s " ) ; // expected-warning{{more '%' conversions than data arguments}}
2010-01-29 20:55:36 +00:00
printf ( " %@ " , 12 ) ; // expected-warning{{invalid conversion specifier '@'}}
printf ( " \0 " ) ; // expected-warning{{format string contains '\0' within the string body}}
printf ( " xs \0 " ) ; // expected-warning{{format string contains '\0' within the string body}}
printf ( " %*d \n " ) ; // expected-warning{{'*' specified field width is missing a matching 'int' argument}}
printf ( " %*.*d \n " , x ) ; // expected-warning{{'.*' specified field precision is missing a matching 'int' argument}}
printf ( " %*d \n " , f , x ) ; // expected-warning{{field width should have type 'int', but argument has type 'double'}}
printf ( " %*.*d \n " , x , f , x ) ; // expected-warning{{field precision should have type 'int', but argument has type 'double'}}
printf ( " %** \n " ) ; // expected-warning{{invalid conversion specifier '*'}}
printf ( " %d%d \n " , x ) ; // expected-warning{{more '%' conversions than data arguments}}
2010-02-26 19:18:41 +00:00
printf ( " %d \n " , x , x ) ; // expected-warning{{data argument not used by format string}}
2016-12-15 18:54:00 +00:00
printf ( " %W%d \n " , x , x ) ; // expected-warning{{invalid conversion specifier 'W'}} expected-warning {{data argument not used by format string}}
2010-01-29 20:55:36 +00:00
printf ( " % " ) ; // expected-warning{{incomplete format specifier}}
printf ( " %.d " , x ) ; // no-warning
printf ( " %. " , x ) ; // expected-warning{{incomplete format specifier}}
2012-01-20 21:52:58 +00:00
printf ( " %f " , 4 ) ; // expected-warning{{format specifies type 'double' but the argument has type 'int'}}
2012-02-16 16:34:54 +00:00
printf ( " %qd " , lli ) ; // no-warning
printf ( " %qd " , x ) ; // expected-warning{{format specifies type 'long long' but the argument has type 'int'}}
printf ( " %qp " , ( void * ) 0 ) ; // expected-warning{{length modifier 'q' results in undefined behavior or no effect with 'p' conversion specifier}}
2010-02-01 19:28:15 +00:00
printf ( " hhX %hhX " , ( unsigned char ) 10 ) ; // no-warning
printf ( " llX %llX " , ( long long ) 10 ) ; // no-warning
2023-04-20 09:34:34 -07:00
printf ( " %lb %lB " , ( long ) 10 , ( long ) 10 ) ; // no-warning
2022-08-04 10:26:31 -07:00
printf ( " %llb %llB " , ( long long ) 10 , ( long long ) 10 ) ; // no-warning
2010-02-01 19:28:15 +00:00
// This is fine, because there is an implicit conversion to an int.
printf ( " %d " , ( unsigned char ) 10 ) ; // no-warning
2012-01-20 21:52:58 +00:00
printf ( " %d " , ( long long ) 10 ) ; // expected-warning{{format specifies type 'int' but the argument has type 'long long'}}
2010-02-01 23:23:50 +00:00
printf ( " %Lf \n " , ( long double ) 1.0 ) ; // no-warning
2012-01-20 21:52:58 +00:00
printf ( " %f \n " , ( long double ) 1.0 ) ; // expected-warning{{format specifies type 'double' but the argument has type 'long double'}}
2010-03-01 19:22:33 +00:00
// The man page says that a zero precision is okay.
printf ( " %.0Lf " , ( long double ) 1.0 ) ; // no-warning
2012-01-20 21:52:58 +00:00
printf ( " %c \n " , " x " ) ; // expected-warning{{format specifies type 'int' but the argument has type 'char *'}}
printf ( " %c \n " , 1.23 ) ; // expected-warning{{format specifies type 'int' but the argument has type 'double'}}
2016-12-15 18:54:00 +00:00
printf ( " Format %d, is %! %f " , 1 , 4.4 ) ; // expected-warning{{invalid conversion specifier '!'}}
2010-10-21 04:00:58 +00:00
}
typedef unsigned char uint8_t ;
2022-02-04 15:19:56 -05:00
void should_understand_small_integers ( void ) {
2012-01-20 21:52:58 +00:00
printf ( " %hhu " , ( short ) 10 ) ; // expected-warning{{format specifies type 'unsigned char' but the argument has type 'short'}}
2019-08-23 18:01:57 +00:00
printf ( " %hu \n " , ( unsigned char ) 1 ) ; // warning with -Wformat-pedantic only
printf ( " %hu \n " , ( uint8_t ) 1 ) ; // warning with -Wformat-pedantic only
2010-10-21 04:00:58 +00:00
}
2010-01-29 20:55:36 +00:00
2010-02-11 09:27:41 +00:00
void test11 ( void * p , char * s ) {
printf ( " %p " , p ) ; // no-warning
2012-01-20 21:52:58 +00:00
printf ( " %p " , 123 ) ; // expected-warning{{format specifies type 'void *' but the argument has type 'int'}}
2010-06-17 19:00:27 +00:00
printf ( " %.4p " , p ) ; // expected-warning{{precision used with 'p' conversion specifier, resulting in undefined behavior}}
printf ( " %+p " , p ) ; // expected-warning{{flag '+' results in undefined behavior with 'p' conversion specifier}}
printf ( " % p " , p ) ; // expected-warning{{flag ' ' results in undefined behavior with 'p' conversion specifier}}
printf ( " %0p " , p ) ; // expected-warning{{flag '0' results in undefined behavior with 'p' conversion specifier}}
2010-02-11 09:27:41 +00:00
printf ( " %s " , s ) ; // no-warning
2010-06-17 19:00:27 +00:00
printf ( " %+s " , p ) ; // expected-warning{{flag '+' results in undefined behavior with 's' conversion specifier}}
2020-07-10 13:22:11 -04:00
// expected-warning@-1 {{format specifies type 'char *' but the argument has type 'void *'}}
2010-06-17 19:00:27 +00:00
printf ( " % s " , p ) ; // expected-warning{{flag ' ' results in undefined behavior with 's' conversion specifier}}
2020-07-10 13:22:11 -04:00
// expected-warning@-1 {{format specifies type 'char *' but the argument has type 'void *'}}
2010-06-17 19:00:27 +00:00
printf ( " %0s " , p ) ; // expected-warning{{flag '0' results in undefined behavior with 's' conversion specifier}}
2020-07-10 13:22:11 -04:00
// expected-warning@-1 {{format specifies type 'char *' but the argument has type 'void *'}}
2010-02-11 09:27:41 +00:00
}
2010-02-16 02:14:24 +00:00
void test12 ( char * b ) {
2010-02-16 01:46:59 +00:00
unsigned char buf [ 4 ] ;
printf ( " %.4s \n " , buf ) ; // no-warning
2012-01-20 21:52:58 +00:00
printf ( " %.4s \n " , & buf ) ; // expected-warning{{format specifies type 'char *' but the argument has type 'unsigned char (*)[4]'}}
2022-07-22 15:24:54 -04:00
2010-02-16 02:14:24 +00:00
// Verify that we are checking asprintf
2012-01-20 21:52:58 +00:00
asprintf ( & b , " %d " , " asprintf " ) ; // expected-warning{{format specifies type 'int' but the argument has type 'char *'}}
2010-02-16 01:46:59 +00:00
}
2011-10-25 04:20:41 +00:00
void test13 ( short x ) {
char bel = 007 ;
printf ( " bel: '0%hhd' \n " , bel ) ; // no-warning
2012-01-20 21:52:58 +00:00
printf ( " x: '0%hhd' \n " , x ) ; // expected-warning {{format specifies type 'char' but the argument has type 'short'}}
2011-10-25 04:20:41 +00:00
}
2010-01-30 00:49:51 +00:00
typedef struct __aslclient * aslclient ;
typedef struct __aslmsg * aslmsg ;
int asl_log ( aslclient asl , aslmsg msg , int level , const char * format , . . . ) __attribute__ ( ( __format__ ( __printf__ , 4 , 5 ) ) ) ;
void test_asl ( aslclient asl ) {
asl_log ( asl , 0 , 3 , " Error: %m " ) ; // no-warning
asl_log ( asl , 0 , 3 , " Error: %W " ) ; // expected-warning{{invalid conversion specifier 'W'}}
}
2010-02-02 20:10:50 +00:00
typedef enum { A } int_t ;
void f0 ( int_t x ) { printf ( " %d \n " , x ) ; }
2010-02-24 00:05:54 +00:00
// Unicode test cases. These are possibly specific to Mac OS X. If so, they should
// eventually be moved into a separate test.
void test_unicode_conversions ( wchar_t * s ) {
printf ( " %S " , s ) ; // no-warning
2012-01-20 21:52:58 +00:00
printf ( " %s " , s ) ; // expected-warning{{format specifies type 'char *' but the argument has type 'wchar_t *'}}
2010-02-24 00:05:54 +00:00
printf ( " %C " , s [ 0 ] ) ; // no-warning
Clang :: Sema/wchar.c has long been failing on Solaris:
error: 'error' diagnostics expected but not seen:
File /vol/llvm/src/clang/local/test/Sema/wchar.c Line 22: initializing wide char array with non-wide string literal
error: 'error' diagnostics seen but not expected:
File /vol/llvm/src/clang/local/test/Sema/wchar.c Line 20: array initializer must be an initializer list
File /vol/llvm/src/clang/local/test/Sema/wchar.c Line 22: array initializer must be an initializer list
It turns out the definition is wrong, as can be seen in GCC's gcc/config/sol2.h:
/* wchar_t is called differently in <wchar.h> for 32 and 64-bit
compilations. This is called for by SCD 2.4.1, p. 6-83, Figure 6-65
(32-bit) and p. 6P-10, Figure 6.38 (64-bit). */
#undef WCHAR_TYPE
#define WCHAR_TYPE (TARGET_64BIT ? "int" : "long int")
The following patch implements this, and at the same time corrects the wint_t
definition which is the same:
/* Same for wint_t. See SCD 2.4.1, p. 6-83, Figure 6-66 (32-bit). There's
no corresponding 64-bit definition, but this is what Solaris 8
<iso/wchar_iso.h> uses. */
#undef WINT_TYPE
#define WINT_TYPE (TARGET_64BIT ? "int" : "long int")
Clang :: Preprocessor/wchar_t.c and Clang :: Sema/format-strings.c need to
be adjusted to account for that.
Tested on i386-pc-solaris2.11, x86_64-pc-solaris2.11, and x86_64-pc-linux-gnu.
Differential Revision: https://reviews.llvm.org/D62944
llvm-svn: 363612
2019-06-17 20:21:25 +00:00
# if defined(__sun) && !defined(__LP64__)
printf ( " %c " , s [ 0 ] ) ; // expected-warning{{format specifies type 'int' but the argument has type 'wchar_t' (aka 'long')}}
# else
2010-02-24 00:05:54 +00:00
printf ( " %c " , s [ 0 ] ) ;
Clang :: Sema/wchar.c has long been failing on Solaris:
error: 'error' diagnostics expected but not seen:
File /vol/llvm/src/clang/local/test/Sema/wchar.c Line 22: initializing wide char array with non-wide string literal
error: 'error' diagnostics seen but not expected:
File /vol/llvm/src/clang/local/test/Sema/wchar.c Line 20: array initializer must be an initializer list
File /vol/llvm/src/clang/local/test/Sema/wchar.c Line 22: array initializer must be an initializer list
It turns out the definition is wrong, as can be seen in GCC's gcc/config/sol2.h:
/* wchar_t is called differently in <wchar.h> for 32 and 64-bit
compilations. This is called for by SCD 2.4.1, p. 6-83, Figure 6-65
(32-bit) and p. 6P-10, Figure 6.38 (64-bit). */
#undef WCHAR_TYPE
#define WCHAR_TYPE (TARGET_64BIT ? "int" : "long int")
The following patch implements this, and at the same time corrects the wint_t
definition which is the same:
/* Same for wint_t. See SCD 2.4.1, p. 6-83, Figure 6-66 (32-bit). There's
no corresponding 64-bit definition, but this is what Solaris 8
<iso/wchar_iso.h> uses. */
#undef WINT_TYPE
#define WINT_TYPE (TARGET_64BIT ? "int" : "long int")
Clang :: Preprocessor/wchar_t.c and Clang :: Sema/format-strings.c need to
be adjusted to account for that.
Tested on i386-pc-solaris2.11, x86_64-pc-solaris2.11, and x86_64-pc-linux-gnu.
Differential Revision: https://reviews.llvm.org/D62944
llvm-svn: 363612
2019-06-17 20:21:25 +00:00
# endif
2010-02-24 02:28:29 +00:00
// FIXME: This test reports inconsistent results. On Windows, '%C' expects
// 'unsigned short'.
// printf("%C", 10);
2010-02-24 00:05:54 +00:00
printf ( " %S " , " hello " ) ; // expected-warning{{but the argument has type 'char *'}}
}
2010-02-27 01:41:03 +00:00
// Mac OS X supports positional arguments in format strings.
// This is an IEEE extension (IEEE Std 1003.1).
// FIXME: This is probably not portable everywhere.
2022-02-04 15:19:56 -05:00
void test_positional_arguments ( void ) {
2010-02-27 01:41:03 +00:00
printf ( " %0$ " , ( int ) 2 ) ; // expected-warning{{position arguments in format strings start counting at 1 (not 0)}}
2010-03-01 19:22:33 +00:00
printf ( " %1$*0$d " , ( int ) 2 ) ; // expected-warning{{position arguments in format strings start counting at 1 (not 0)}}
2010-02-27 01:41:03 +00:00
printf ( " %1$d " , ( int ) 2 ) ; // no-warning
printf ( " %1$d " , ( int ) 2 , 2 ) ; // expected-warning{{data argument not used by format string}}
2012-01-20 21:52:58 +00:00
printf ( " %1$d%1$f " , ( int ) 2 ) ; // expected-warning{{format specifies type 'double' but the argument has type 'int'}}
2010-02-27 01:41:03 +00:00
printf ( " %1$2.2d " , ( int ) 2 ) ; // no-warning
printf ( " %2$*1$.2d " , ( int ) 2 , ( int ) 3 ) ; // no-warning
printf ( " %2$*8$d " , ( int ) 2 , ( int ) 3 ) ; // expected-warning{{specified field width is missing a matching 'int' argument}}
2010-07-19 22:01:06 +00:00
printf ( " %%%1$d " , ( int ) 2 ) ; // no-warning
printf ( " %1$d%% " , ( int ) 2 ) ; // no-warning
2010-02-27 01:41:03 +00:00
}
2010-03-25 03:59:12 +00:00
// PR 6697 - Handle format strings where the data argument is not adjacent to the format string
void myprintf_PR_6697 ( const char * format , int x , . . . ) __attribute__ ( ( __format__ ( printf , 1 , 3 ) ) ) ;
2022-02-04 15:19:56 -05:00
void test_pr_6697 ( void ) {
2010-03-25 03:59:12 +00:00
myprintf_PR_6697 ( " %s \n " , 1 , " foo " ) ; // no-warning
2012-01-20 21:52:58 +00:00
myprintf_PR_6697 ( " %s \n " , 1 , ( int ) 0 ) ; // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
2010-03-25 03:59:12 +00:00
// FIXME: Not everything should clearly support positional arguments,
// but we need a way to identify those cases.
myprintf_PR_6697 ( " %1$s \n " , 1 , " foo " ) ; // no-warning
myprintf_PR_6697 ( " %2$s \n " , 1 , " foo " ) ; // expected-warning{{data argument position '2' exceeds the number of data arguments (1)}}
myprintf_PR_6697 ( " %18$s \n " , 1 , " foo " ) ; // expected-warning{{data argument position '18' exceeds the number of data arguments (1)}}
2012-01-20 21:52:58 +00:00
myprintf_PR_6697 ( " %1$s \n " , 1 , ( int ) 0 ) ; // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
2010-03-25 03:59:12 +00:00
}
2010-05-26 05:35:51 +00:00
void rdar8026030 ( FILE * fp ) {
fprintf ( fp , " \ % " ) ; // expected-warning{{incomplete format specifier}}
}
2010-06-17 19:00:27 +00:00
2022-02-04 15:19:56 -05:00
void bug7377_bad_length_mod_usage ( void ) {
2010-06-17 19:00:27 +00:00
// Bad length modifiers
printf ( " %hhs " , " foo " ) ; // expected-warning{{length modifier 'hh' results in undefined behavior or no effect with 's' conversion specifier}}
printf ( " %1$zp " , ( void * ) 0 ) ; // expected-warning{{length modifier 'z' results in undefined behavior or no effect with 'p' conversion specifier}}
printf ( " %ls " , L " foo " ) ; // no-warning
printf ( " %#.2Lf " , ( long double ) 1.234 ) ; // no-warning
// Bad flag usage
printf ( " %#p " , ( void * ) 0 ) ; // expected-warning{{flag '#' results in undefined behavior with 'p' conversion specifier}}
printf ( " %0d " , - 1 ) ; // no-warning
2022-08-04 10:26:31 -07:00
printf ( " %0b%0B " , - 1u , - 1u ) ; // no-warning
2022-01-21 21:00:39 +00:00
printf ( " %-p " , ( void * ) 0 ) ; // no-warning
# if !defined(__ANDROID__) && !defined(__Fuchsia__)
2012-07-30 20:21:58 +00:00
printf ( " %#n " , ( int * ) 0 ) ; // expected-warning{{flag '#' results in undefined behavior with 'n' conversion specifier}}
printf ( " %-n " , ( int * ) 0 ) ; // expected-warning{{flag '-' results in undefined behavior with 'n' conversion specifier}}
2022-01-21 21:00:39 +00:00
# else
printf ( " %#n " , ( int * ) 0 ) ; // expected-warning{{flag '#' results in undefined behavior with 'n' conversion specifier}}
// expected-warning@-1 {{'%n' specifier not supported on this platform}}
printf ( " %-n " , ( int * ) 0 ) ; // expected-warning{{flag '-' results in undefined behavior with 'n' conversion specifier}}
// expected-warning@-1 {{'%n' specifier not supported on this platform}}
# endif // !defined(__ANDROID__) && !defined(__Fuchsia__)
2010-06-17 19:00:27 +00:00
// Bad optional amount use
printf ( " %.2c " , ' a ' ) ; // expected-warning{{precision used with 'c' conversion specifier, resulting in undefined behavior}}
2022-01-21 21:00:39 +00:00
# if !defined(__ANDROID__) && !defined(__Fuchsia__)
printf ( " %1n " , ( int * ) 0 ) ; // expected-warning{{field width used with 'n' conversion specifier, resulting in undefined behavior}}
printf ( " %.9n " , ( int * ) 0 ) ; // expected-warning{{precision used with 'n' conversion specifier, resulting in undefined behavior}}
# else
2012-07-30 20:21:58 +00:00
printf ( " %1n " , ( int * ) 0 ) ; // expected-warning{{field width used with 'n' conversion specifier, resulting in undefined behavior}}
2022-01-21 21:00:39 +00:00
// expected-warning@-1 {{'%n' specifier not supported on this platform}}
2012-07-30 20:21:58 +00:00
printf ( " %.9n " , ( int * ) 0 ) ; // expected-warning{{precision used with 'n' conversion specifier, resulting in undefined behavior}}
2022-01-21 21:00:39 +00:00
// expected-warning@-1 {{'%n' specifier not supported on this platform}}
# endif // #if !defined(__ANDROID__) && !defined(__Fuchsia__)
2010-06-17 19:00:27 +00:00
// Ignored flags
printf ( " % +f " , 1.23 ) ; // expected-warning{{flag ' ' is ignored when flag '+' is present}}
printf ( " %+ f " , 1.23 ) ; // expected-warning{{flag ' ' is ignored when flag '+' is present}}
printf ( " %0-f " , 1.23 ) ; // expected-warning{{flag '0' is ignored when flag '-' is present}}
printf ( " %-0f " , 1.23 ) ; // expected-warning{{flag '0' is ignored when flag '-' is present}}
printf ( " %-+f " , 1.23 ) ; // no-warning
}
2010-08-24 22:24:51 +00:00
// PR 7981 - handle '%lc' (wint_t)
void pr7981 ( wint_t c , wchar_t c2 ) {
printf ( " %lc " , c ) ; // no-warning
printf ( " %lc " , 1.0 ) ; // expected-warning{{the argument has type 'double'}}
Clang :: Sema/wchar.c has long been failing on Solaris:
error: 'error' diagnostics expected but not seen:
File /vol/llvm/src/clang/local/test/Sema/wchar.c Line 22: initializing wide char array with non-wide string literal
error: 'error' diagnostics seen but not expected:
File /vol/llvm/src/clang/local/test/Sema/wchar.c Line 20: array initializer must be an initializer list
File /vol/llvm/src/clang/local/test/Sema/wchar.c Line 22: array initializer must be an initializer list
It turns out the definition is wrong, as can be seen in GCC's gcc/config/sol2.h:
/* wchar_t is called differently in <wchar.h> for 32 and 64-bit
compilations. This is called for by SCD 2.4.1, p. 6-83, Figure 6-65
(32-bit) and p. 6P-10, Figure 6.38 (64-bit). */
#undef WCHAR_TYPE
#define WCHAR_TYPE (TARGET_64BIT ? "int" : "long int")
The following patch implements this, and at the same time corrects the wint_t
definition which is the same:
/* Same for wint_t. See SCD 2.4.1, p. 6-83, Figure 6-66 (32-bit). There's
no corresponding 64-bit definition, but this is what Solaris 8
<iso/wchar_iso.h> uses. */
#undef WINT_TYPE
#define WINT_TYPE (TARGET_64BIT ? "int" : "long int")
Clang :: Preprocessor/wchar_t.c and Clang :: Sema/format-strings.c need to
be adjusted to account for that.
Tested on i386-pc-solaris2.11, x86_64-pc-solaris2.11, and x86_64-pc-linux-gnu.
Differential Revision: https://reviews.llvm.org/D62944
llvm-svn: 363612
2019-06-17 20:21:25 +00:00
# if __WINT_WIDTH__ == 32 && !(defined(__sun) && !defined(__LP64__))
2010-08-24 22:24:51 +00:00
printf ( " %lc " , ( char ) 1 ) ; // no-warning
2018-09-19 18:13:34 +00:00
# else
printf ( " %lc " , ( char ) 1 ) ; // expected-warning{{the argument has type 'char'}}
# endif
2012-05-04 10:55:22 +00:00
printf ( " %lc " , & c ) ; // expected-warning{{the argument has type 'wint_t *'}}
2012-05-04 11:23:40 +00:00
// If wint_t and wchar_t are the same width and wint_t is signed where
// wchar_t is unsigned, an implicit conversion isn't possible.
# if defined(__WINT_UNSIGNED__) || !defined(__WCHAR_UNSIGNED__) || \
__WINT_WIDTH__ > __WCHAR_WIDTH__
2010-08-24 22:24:51 +00:00
printf ( " %lc " , c2 ) ; // no-warning
2012-05-04 11:23:40 +00:00
# endif
2010-08-24 22:24:51 +00:00
}
[clang] Remove rdar links; NFC
We have a new policy in place making links to private resources
something we try to avoid in source and test files. Normally, we'd
organically switch to the new policy rather than make a sweeping change
across a project. However, Clang is in a somewhat special circumstance
currently: recently, I've had several new contributors run into rdar
links around test code which their patch was changing the behavior of.
This turns out to be a surprisingly bad experience, especially for
newer folks, for a handful of reasons: not understanding what the link
is and feeling intimidated by it, wondering whether their changes are
actually breaking something important to a downstream in some way,
having to hunt down strangers not involved with the patch to impose on
them for help, accidental pressure from asking for potentially private
IP to be made public, etc. Because folks run into these links entirely
by chance (through fixing bugs or working on new features), there's not
really a set of problematic links to focus on -- all of the links have
basically the same potential for causing these problems. As a result,
this is an omnibus patch to remove all such links.
This was not a mechanical change; it was done by manually searching for
rdar, radar, radr, and other variants to find all the various
problematic links. From there, I tried to retain or reword the
surrounding comments so that we would lose as little context as
possible. However, because most links were just a plain link with no
supporting context, the majority of the changes are simple removals.
Differential Review: https://reviews.llvm.org/D158071
2023-08-28 12:13:42 -04:00
// -Wformat-security says NULL is not a string literal
2022-02-04 15:19:56 -05:00
void rdar8269537 ( void ) {
2010-09-09 03:51:42 +00:00
// This is likely to crash in most cases, but -Wformat-nonliteral technically
// doesn't warn in this case.
printf ( 0 ) ; // no-warning
}
2010-09-09 04:33:05 +00:00
// Handle functions with multiple format attributes.
extern void rdar8332221_vprintf_scanf ( const char * , va_list , const char * , . . . )
__attribute__ ( ( __format__ ( __printf__ , 1 , 0 ) ) )
__attribute__ ( ( __format__ ( __scanf__ , 3 , 4 ) ) ) ;
2022-07-22 15:24:54 -04:00
2010-09-09 04:33:05 +00:00
void rdar8332221 ( va_list ap , int * x , long * y ) {
rdar8332221_vprintf_scanf ( " % " , ap , " %d " , x ) ; // expected-warning{{incomplete format specifier}}
}
2025-03-06 09:12:22 -08:00
void rdar8332221_vprintf_scanf ( const char * p , va_list ap , const char * s , . . . ) {
vprintf ( p , ap ) ;
va_list vs ;
va_start ( vs , s ) ;
vscanf ( s , vs ) ;
va_end ( vs ) ;
}
__attribute__ ( ( __format__ ( __printf__ , 1 , 0 ) ) )
__attribute__ ( ( __format__ ( __scanf__ , 3 , 4 ) ) )
void vprintf_scanf_bad ( const char * p , va_list ap , const char * s , . . . ) {
vscanf ( p , ap ) ; // expected-warning{{passing 'printf' format string where 'scanf' format string is expected}}
va_list vs ;
va_start ( vs , s ) ;
vprintf ( s , vs ) ; // expected-warning{{passing 'scanf' format string where 'printf' format string is expected}}
va_end ( vs ) ;
}
2010-11-21 18:34:21 +00:00
// PR8641
2022-02-04 15:19:56 -05:00
void pr8641 ( void ) {
2010-11-21 18:34:21 +00:00
printf ( " %#x \n " , 10 ) ;
printf ( " %#X \n " , 10 ) ;
2022-08-04 10:26:31 -07:00
printf ( " %#b %#15.8B \n " , 10 , 10u ) ;
2010-11-21 18:34:21 +00:00
}
2011-01-08 05:28:38 +00:00
2022-02-04 15:19:56 -05:00
void posix_extensions ( void ) {
2011-01-08 05:28:38 +00:00
// Test %'d, "thousands grouping".
printf ( " %'d \n " , 123456789 ) ; // no-warning
2011-01-08 05:28:46 +00:00
printf ( " %'i \n " , 123456789 ) ; // no-warning
printf ( " %'f \n " , ( float ) 1.0 ) ; // no-warning
printf ( " %'p \n " , ( void * ) 0 ) ; // expected-warning{{results in undefined behavior with 'p' conversion specifier}}
2022-08-04 10:26:31 -07:00
printf ( " %'b \n " , 123456789 ) ; // expected-warning{{results in undefined behavior with 'b' conversion specifier}}
printf ( " %'B \n " , 123456789 ) ; // expected-warning{{results in undefined behavior with 'B' conversion specifier}}
2011-01-08 05:28:38 +00:00
}
2011-02-21 00:07:51 +00:00
// PR8486
//
// Test what happens when -Wformat is on, but -Wformat-security is off.
# pragma GCC diagnostic warning "-Wformat"
# pragma GCC diagnostic ignored "-Wformat-security"
2022-02-04 15:19:56 -05:00
void pr8486 ( void ) {
2012-01-20 21:52:58 +00:00
printf ( " %s " , 1 ) ; // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
2011-02-21 00:07:51 +00:00
}
2011-02-24 23:03:04 +00:00
// PR9314
// Don't warn about string literals that are PreDefinedExprs, e.g. __func__.
2022-02-04 15:19:56 -05:00
void pr9314 ( void ) {
2011-02-24 23:03:04 +00:00
printf ( __PRETTY_FUNCTION__ ) ; // no-warning
printf ( __func__ ) ; // no-warning
}
2011-06-15 05:45:11 +00:00
int printf ( const char * restrict , . . . ) __attribute__ ( ( __format__ ( __printf__ , 1 , 2 ) ) ) ;
void rdar9612060 ( void ) {
2012-01-20 21:52:58 +00:00
printf ( " %s " , 2 ) ; // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
2011-06-15 05:45:11 +00:00
}
2011-07-13 17:25:47 +00:00
void check_char ( unsigned char x , signed char y ) {
printf ( " %c " , y ) ; // no-warning
printf ( " %hhu " , x ) ; // no-warning
printf ( " %hhi " , y ) ; // no-warning
2011-07-13 17:35:14 +00:00
printf ( " %hhi " , x ) ; // no-warning
2011-07-13 17:25:47 +00:00
printf ( " %c " , x ) ; // no-warning
2011-07-13 17:35:14 +00:00
printf ( " %hhu " , y ) ; // no-warning
2022-08-04 10:26:31 -07:00
printf ( " %hhb %hhB " , x , x ) ; // no-warning
2011-07-13 17:25:47 +00:00
}
2011-08-27 00:16:45 +00:00
// Test suppression of individual warnings.
2022-02-04 15:19:56 -05:00
void test_suppress_invalid_specifier ( void ) {
2011-08-27 00:16:45 +00:00
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wformat-invalid-specifier"
printf ( " %@ " , 12 ) ; // no-warning
# pragma clang diagnostic pop
}
2011-10-28 00:41:25 +00:00
// Make sure warnings are on for next test.
# pragma GCC diagnostic warning "-Wformat"
# pragma GCC diagnostic warning "-Wformat-security"
// Test that the printf call site is where the warning is attached. If the
// format string is somewhere else, point to it in a note.
2022-02-04 15:19:56 -05:00
void pr9751 ( void ) {
2011-10-28 00:41:25 +00:00
const char kFormat1 [ ] = " %d %d \n " ; // expected-note{{format string is defined here}}}
printf ( kFormat1 , 0 ) ; // expected-warning{{more '%' conversions than data arguments}}
printf ( " %d %s \n " , 0 ) ; // expected-warning{{more '%' conversions than data arguments}}
const char kFormat2 [ ] = " %18$s \n " ; // expected-note{{format string is defined here}}
printf ( kFormat2 , 1 , " foo " ) ; // expected-warning{{data argument position '18' exceeds the number of data arguments (2)}}
printf ( " %18$s \n " , 1 , " foo " ) ; // expected-warning{{data argument position '18' exceeds the number of data arguments (2)}}
const char kFormat4 [ ] = " %y " ; // expected-note{{format string is defined here}}
printf ( kFormat4 , 5 ) ; // expected-warning{{invalid conversion specifier 'y'}}
printf ( " %y " , 5 ) ; // expected-warning{{invalid conversion specifier 'y'}}
const char kFormat5 [ ] = " %. " ; // expected-note{{format string is defined here}}
printf ( kFormat5 , 5 ) ; // expected-warning{{incomplete format specifier}}
printf ( " %. " , 5 ) ; // expected-warning{{incomplete format specifier}}
const char kFormat6 [ ] = " %s " ; // expected-note{{format string is defined here}}
2012-01-20 21:52:58 +00:00
printf ( kFormat6 , 5 ) ; // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
printf ( " %s " , 5 ) ; // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
2011-10-28 00:41:25 +00:00
const char kFormat7 [ ] = " %0$ " ; // expected-note{{format string is defined here}}
printf ( kFormat7 , 5 ) ; // expected-warning{{position arguments in format strings start counting at 1 (not 0)}}
printf ( " %0$ " , 5 ) ; // expected-warning{{position arguments in format strings start counting at 1 (not 0)}}
const char kFormat8 [ ] = " %1$d %d " ; // expected-note{{format string is defined here}}
printf ( kFormat8 , 4 , 4 ) ; // expected-warning{{cannot mix positional and non-positional arguments in format string}}
printf ( " %1$d %d " , 4 , 4 ) ; // expected-warning{{cannot mix positional and non-positional arguments in format string}}
const char kFormat9 [ ] = " " ; // expected-note{{format string is defined here}}
printf ( kFormat9 , 4 , 4 ) ; // expected-warning{{format string is empty}}
printf ( " " , 4 , 4 ) ; // expected-warning{{format string is empty}}
const char kFormat10 [ ] = " \0 %d " ; // expected-note{{format string is defined here}}
printf ( kFormat10 , 4 ) ; // expected-warning{{format string contains '\0' within the string body}}
printf ( " \0 %d " , 4 ) ; // expected-warning{{format string contains '\0' within the string body}}
const char kFormat11 [ ] = " %*d " ; // expected-note{{format string is defined here}}
printf ( kFormat11 ) ; // expected-warning{{'*' specified field width is missing a matching 'int' argument}}
printf ( " %*d " ) ; // expected-warning{{'*' specified field width is missing a matching 'int' argument}}
const char kFormat12 [ ] = " %*d " ; // expected-note{{format string is defined here}}
printf ( kFormat12 , 4.4 ) ; // expected-warning{{field width should have type 'int', but argument has type 'double'}}
printf ( " %*d " , 4.4 ) ; // expected-warning{{field width should have type 'int', but argument has type 'double'}}
const char kFormat13 [ ] = " %.3p " ; // expected-note{{format string is defined here}}
void * p ;
printf ( kFormat13 , p ) ; // expected-warning{{precision used with 'p' conversion specifier, resulting in undefined behavior}}
printf ( " %.3p " , p ) ; // expected-warning{{precision used with 'p' conversion specifier, resulting in undefined behavior}}
const char kFormat14 [ ] = " %0s " ; // expected-note{{format string is defined here}}
printf ( kFormat14 , " a " ) ; // expected-warning{{flag '0' results in undefined behavior with 's' conversion specifier}}
printf ( " %0s " , " a " ) ; // expected-warning{{flag '0' results in undefined behavior with 's' conversion specifier}}
const char kFormat15 [ ] = " %hhs " ; // expected-note{{format string is defined here}}
printf ( kFormat15 , " a " ) ; // expected-warning{{length modifier 'hh' results in undefined behavior or no effect with 's' conversion specifier}}
printf ( " %hhs " , " a " ) ; // expected-warning{{length modifier 'hh' results in undefined behavior or no effect with 's' conversion specifier}}
const char kFormat16 [ ] = " %-0d " ; // expected-note{{format string is defined here}}
printf ( kFormat16 , 5 ) ; // expected-warning{{flag '0' is ignored when flag '-' is present}}
printf ( " %-0d " , 5 ) ; // expected-warning{{flag '0' is ignored when flag '-' is present}}
// Make sure that the "format string is defined here" note is not emitted
// when the original string is within the argument expression.
2016-02-26 15:35:16 +00:00
printf ( 1 ? " yes %d " : " no %d " ) ; // expected-warning{{more '%' conversions than data arguments}}
2012-01-31 18:12:08 +00:00
const char kFormat17 [ ] = " %hu " ; // expected-note{{format string is defined here}}}
printf ( kFormat17 , ( int [ ] ) { 0 } ) ; // expected-warning{{format specifies type 'unsigned short' but the argument}}
2012-02-13 10:32:27 +00:00
printf ( " %a " , ( long double ) 0 ) ; // expected-warning{{format specifies type 'double' but the argument has type 'long double'}}
2012-05-11 22:10:59 +00:00
// Test braced char[] initializers.
2012-05-17 00:03:16 +00:00
const char kFormat18 [ ] = { " %lld " } ; // expected-note{{format string is defined here}}
2012-05-11 22:10:59 +00:00
printf ( kFormat18 , 0 ) ; // expected-warning{{format specifies type}}
2012-05-17 00:03:16 +00:00
// Make sure we point at the offending argument rather than the format string.
const char kFormat19 [ ] = " %d " ; // expected-note{{format string is defined here}}
printf ( kFormat19 ,
0.0 ) ; // expected-warning{{format specifies}}
2011-10-28 00:41:25 +00:00
}
2012-01-24 21:29:54 +00:00
2022-02-04 15:19:56 -05:00
void pr18905 ( void ) {
2014-02-20 17:05:38 +00:00
const char s1 [ ] = " s \0 %s " ; // expected-note{{format string is defined here}}
const char s2 [ 1 ] = " s " ; // expected-note{{format string is defined here}}
const char s3 [ 2 ] = " s \0 %s " ; // expected-warning{{initializer-string for char array is too long}}
const char s4 [ 10 ] = " s " ;
const char s5 [ 0 ] = " %s " ; // expected-warning{{initializer-string for char array is too long}}
// expected-note@-1{{format string is defined here}}
printf ( s1 ) ; // expected-warning{{format string contains '\0' within the string body}}
printf ( s2 ) ; // expected-warning{{format string is not null-terminated}}
printf ( s3 ) ; // no-warning
printf ( s4 ) ; // no-warning
printf ( s5 ) ; // expected-warning{{format string is not null-terminated}}
}
2012-01-30 08:46:47 +00:00
void __attribute__ ( ( format ( strfmon , 1 , 2 ) ) ) monformat ( const char * fmt , . . . ) ;
void __attribute__ ( ( format ( strftime , 1 , 0 ) ) ) dateformat ( const char * fmt ) ;
// Other formats
2022-02-04 15:19:56 -05:00
void test_other_formats ( void ) {
2012-01-30 08:46:47 +00:00
char * str = " " ;
monformat ( " " , 1 ) ; // expected-warning{{format string is empty}}
2012-02-07 23:10:53 +00:00
monformat ( str ) ; // expected-warning{{format string is not a string literal (potentially insecure)}}
2012-01-30 08:46:47 +00:00
dateformat ( " " ) ; // expected-warning{{format string is empty}}
2013-12-05 04:47:09 +00:00
dateformat ( str ) ; // no-warning (using strftime non-literal is not unsafe)
2012-01-30 08:46:47 +00:00
}
2012-05-03 23:38:51 +00:00
// Do not warn about unused arguments coming from system headers.
# include <format-unused-system-args.h>
void test_unused_system_args ( int x ) {
PRINT1 ( " %d \n " , x ) ; // no-warning{{extra argument is system header is OK}}
}
2012-05-08 17:21:31 +00:00
void pr12761 ( char c ) {
// This should not warn even with -fno-signed-char.
printf ( " %hhx " , c ) ;
}
2012-05-11 00:36:07 +00:00
2018-11-13 22:30:35 +00:00
void test_opencl_vector_format ( int x ) {
printf ( " %v4d " , x ) ; // expected-warning{{invalid conversion specifier 'v'}}
printf ( " %vd " , x ) ; // expected-warning{{invalid conversion specifier 'v'}}
printf ( " %0vd " , x ) ; // expected-warning{{invalid conversion specifier 'v'}}
2019-01-29 20:49:54 +00:00
printf ( " %hlf " , x ) ; // expected-warning{{invalid conversion specifier 'l'}}
printf ( " %hld " , x ) ; // expected-warning{{invalid conversion specifier 'l'}}
2018-11-13 22:30:35 +00:00
}
2012-05-11 00:36:07 +00:00
// Test that we correctly merge the format in both orders.
extern void test14_foo ( const char * , const char * , . . . )
__attribute__ ( ( __format__ ( __printf__ , 1 , 3 ) ) ) ;
extern void test14_foo ( const char * , const char * , . . . )
__attribute__ ( ( __format__ ( __scanf__ , 2 , 3 ) ) ) ;
extern void test14_bar ( const char * , const char * , . . . )
__attribute__ ( ( __format__ ( __scanf__ , 2 , 3 ) ) ) ;
extern void test14_bar ( const char * , const char * , . . . )
__attribute__ ( ( __format__ ( __printf__ , 1 , 3 ) ) ) ;
void test14_zed ( int * p ) {
test14_foo ( " % " , " %d " , p ) ; // expected-warning{{incomplete format specifier}}
test14_bar ( " % " , " %d " , p ) ; // expected-warning{{incomplete format specifier}}
}
2012-07-31 16:37:47 +00:00
2022-01-21 21:00:39 +00:00
# if !defined(__ANDROID__) && !defined(__Fuchsia__)
2012-07-31 16:37:47 +00:00
void test_qualifiers ( volatile int * vip , const int * cip ,
const volatile int * cvip ) {
printf ( " %n " , cip ) ; // expected-warning{{format specifies type 'int *' but the argument has type 'const int *'}}
printf ( " %n " , cvip ) ; // expected-warning{{format specifies type 'int *' but the argument has type 'const volatile int *'}}
printf ( " %n " , vip ) ; // No warning.
printf ( " %p " , cip ) ; // No warning.
printf ( " %p " , cvip ) ; // No warning.
typedef int * ip_t ;
typedef const int * cip_t ;
printf ( " %n " , ( ip_t ) 0 ) ; // No warning.
printf ( " %n " , ( cip_t ) 0 ) ; // expected-warning{{format specifies type 'int *' but the argument has type 'cip_t' (aka 'const int *')}}
}
2013-06-18 18:10:01 +00:00
2022-01-21 21:00:39 +00:00
# else
void test_qualifiers ( volatile int * vip , const int * cip ,
const volatile int * cvip ) {
printf ( " %n " , cip ) ; // expected-warning{{format specifies type 'int *' but the argument has type 'const int *'}}
// expected-warning@-1 {{'%n' specifier not supported on this platform}}
printf ( " %n " , cvip ) ; // expected-warning{{format specifies type 'int *' but the argument has type 'const volatile int *'}}
// expected-warning@-1 {{'%n' specifier not supported on this platform}}
printf ( " %n " , vip ) ; // expected-warning{{'%n' specifier not supported on this platform}}
printf ( " %p " , cip ) ; // No warning.
printf ( " %p " , cvip ) ; // No warning.
typedef int * ip_t ;
typedef const int * cip_t ;
printf ( " %n " , ( ip_t ) 0 ) ; // expected-warning{{'%n' specifier not supported on this platform}}
printf ( " %n " , ( cip_t ) 0 ) ; // expected-warning{{format specifies type 'int *' but the argument has type 'cip_t' (aka 'const int *')}}
// expected-warning@-1 {{'%n' specifier not supported on this platform}}
}
# endif // #if !defined(__ANDROID__) && !defined(__Fuchsia__)
2013-06-18 18:10:01 +00:00
# pragma GCC diagnostic ignored "-Wformat-nonliteral"
# pragma GCC diagnostic warning "-Wformat-security"
extern void test_format_security_extra_args ( const char * , int , . . . )
__attribute__ ( ( __format__ ( __printf__ , 1 , 3 ) ) ) ;
void test_format_security_pos ( char * string ) {
test_format_security_extra_args ( string , 5 ) ; // expected-warning {{format string is not a string literal (potentially insecure)}}
2016-03-15 20:56:38 +00:00
// expected-note@-1{{treat the string as an argument to avoid this}}
2013-06-18 18:10:01 +00:00
}
# pragma GCC diagnostic warning "-Wformat-nonliteral"
2016-09-16 01:07:04 +00:00
void test_char_pointer_arithmetic ( int b ) {
const char s1 [ ] = " string " ;
const char s2 [ ] = " %s string " ;
printf ( s1 - 1 ) ; // expected-warning {{format string is not a string literal (potentially insecure)}}
// expected-note@-1{{treat the string as an argument to avoid this}}
printf ( s1 + 2 ) ; // no-warning
printf ( s2 + 2 ) ; // no-warning
const char s3 [ ] = " %s string " ;
printf ( ( s3 + 2 ) - 2 ) ; // expected-warning{{more '%' conversions than data arguments}}
// expected-note@-2{{format string is defined here}}
printf ( 2 + s2 ) ; // no-warning
printf ( 6 + s2 - 2 ) ; // no-warning
printf ( 2 + ( b ? s1 : s2 ) ) ; // no-warning
const char s5 [ ] = " string %s " ;
printf ( 2 + ( b ? s2 : s5 ) ) ; // expected-warning{{more '%' conversions than data arguments}}
// expected-note@-2{{format string is defined here}}
printf ( 2 + ( b ? s2 : s5 ) , " " ) ; // no-warning
printf ( 2 + ( b ? s1 : s2 - 2 ) , " " ) ; // no-warning
const char s6 [ ] = " %s string " ;
printf ( 2 + ( b ? s1 : s6 - 2 ) ) ; // expected-warning{{more '%' conversions than data arguments}}
// expected-note@-2{{format string is defined here}}
printf ( 1 ? s2 + 2 : s2 ) ; // no-warning
printf ( 0 ? s2 : s2 + 2 ) ; // no-warning
printf ( 2 + s2 + 5 * 3 - 16 , " " ) ; // expected-warning{{data argument not used}}
const char s7 [ ] = " %s string %s %s " ;
printf ( s7 + 3 , " " ) ; // expected-warning{{more '%' conversions than data arguments}}
// expected-note@-2{{format string is defined here}}
}
2016-09-22 00:00:26 +00:00
2022-02-04 15:19:56 -05:00
void PR30481 ( void ) {
2016-09-22 00:00:26 +00:00
// This caused crashes due to invalid casts.
2022-07-22 15:24:54 -04:00
printf ( 1 > 0 ) ; // expected-warning{{format string is not a string literal}} expected-error{{incompatible integer to pointer conversion}} expected-note@format-strings.c:*{{passing argument to parameter here}} expected-note{{to avoid this}}
2016-09-22 00:00:26 +00:00
}
2020-07-10 13:22:11 -04:00
void test_printf_opaque_ptr ( void * op ) {
printf ( " %s " , op ) ; // expected-warning{{format specifies type 'char *' but the argument has type 'void *'}}
}
2021-10-27 15:38:31 -07:00
2022-02-04 15:19:56 -05:00
void test_block ( void ) {
2021-10-27 15:38:31 -07:00
void __attribute__ ( ( __format__ ( __printf__ , 1 , 2 ) ) ) ( ^ printf_arg1 ) (
const char * , . . . ) =
^ ( const char * fmt , . . . ) __attribute__ ( ( __format__ ( __printf__ , 1 , 2 ) ) ) {
va_list ap ;
va_start ( ap , fmt ) ;
vprintf ( fmt , ap ) ;
va_end ( ap ) ;
} ;
printf_arg1 ( " %s string %i \n " , " aaa " , 123 ) ;
printf_arg1 ( " %s string \n " , 123 ) ; // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
void __attribute__ ( ( __format__ ( __printf__ , 2 , 3 ) ) ) ( ^ printf_arg2 ) (
const char * , const char * , . . . ) =
^ ( const char * not_fmt , const char * fmt , . . . )
__attribute__ ( ( __format__ ( __printf__ , 2 , 3 ) ) ) {
va_list ap ;
va_start ( ap , fmt ) ;
Allow non-variadic functions to be attributed with `__attribute__((format))`
Clang only allows you to use __attribute__((format)) on variadic functions. There are legit use cases for __attribute__((format)) on non-variadic functions, such as:
(1) variadic templates
```c++
template<typename… Args>
void print(const char *fmt, Args… &&args) __attribute__((format(1, 2))); // error: format attribute requires variadic function
```
(2) functions which take fixed arguments and a custom format:
```c++
void print_number_string(const char *fmt, unsigned number, const char *string) __attribute__((format(1, 2)));
// ^error: format attribute requires variadic function
void foo(void) {
print_number_string(“%08x %s\n”, 0xdeadbeef, “hello”);
print_number_string(“%d %s”, 0xcafebabe, “bar”);
}
```
This change allows Clang users to attach __attribute__((format)) to non-variadic functions, including functions with C++ variadic templates. It replaces the error with a GCC compatibility warning and improves the type checker to ensure that received arrays are treated like pointers (this is a possibility in C++ since references to template types can bind to arrays).
Reviewed By: aaron.ballman
Differential Revision: https://reviews.llvm.org/D112579
rdar://84629099
2022-06-07 15:45:07 -07:00
vprintf ( fmt , ap ) ;
2021-10-27 15:38:31 -07:00
vprintf ( not_fmt , ap ) ; // expected-warning{{format string is not a string literal}}
va_end ( ap ) ;
} ;
printf_arg2 ( " foo " , " %s string %i \n " , " aaa " , 123 ) ;
printf_arg2 ( " %s string \n " , " foo " , " bar " ) ; // expected-warning{{data argument not used by format string}}
}
2022-08-26 19:26:32 +08:00
void test_promotion ( void ) {
// Default argument promotions for *printf in N2562
// https://github.com/llvm/llvm-project/issues/57102
// N2562: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2562.pdf
int i ;
signed char sc ;
unsigned char uc ;
char c ;
short ss ;
unsigned short us ;
printf ( " %hhd %hd %d %hhd %hd %d " , i , i , i , sc , sc , sc ) ; // no-warning
printf ( " %hhd %hd %d %hhd %hd %d " , uc , uc , uc , c , c , c ) ; // no-warning
// %ld %lld %llx
printf ( " %ld " , i ) ; // expected-warning{{format specifies type 'long' but the argument has type 'int'}}
printf ( " %lld " , i ) ; // expected-warning{{format specifies type 'long long' but the argument has type 'int'}}
printf ( " %ld " , sc ) ; // expected-warning{{format specifies type 'long' but the argument has type 'signed char'}}
printf ( " %lld " , sc ) ; // expected-warning{{format specifies type 'long long' but the argument has type 'signed char'}}
printf ( " %ld " , uc ) ; // expected-warning{{format specifies type 'long' but the argument has type 'unsigned char'}}
printf ( " %lld " , uc ) ; // expected-warning{{format specifies type 'long long' but the argument has type 'unsigned char'}}
printf ( " %llx " , i ) ; // expected-warning{{format specifies type 'unsigned long long' but the argument has type 'int'}}
// ill formed spec for floats
printf ( " %hf " , // expected-warning{{length modifier 'h' results in undefined behavior or no effect with 'f' conversion specifier}}
sc ) ; // expected-warning{{format specifies type 'double' but the argument has type 'signed char'}}
// for %hhd and `short` they are compatible by promotions but more likely misuse
printf ( " %hd " , ss ) ; // no-warning
printf ( " %hhd " , ss ) ; // expected-warning{{format specifies type 'char' but the argument has type 'short'}}
printf ( " %hu " , us ) ; // no-warning
printf ( " %hhu " , ss ) ; // expected-warning{{format specifies type 'unsigned char' but the argument has type 'short'}}
// floats & integers are not compatible
printf ( " %f " , i ) ; // expected-warning{{format specifies type 'double' but the argument has type 'int'}}
printf ( " %f " , sc ) ; // expected-warning{{format specifies type 'double' but the argument has type 'signed char'}}
printf ( " %f " , uc ) ; // expected-warning{{format specifies type 'double' but the argument has type 'unsigned char'}}
printf ( " %f " , c ) ; // expected-warning{{format specifies type 'double' but the argument has type 'char'}}
printf ( " %f " , ss ) ; // expected-warning{{format specifies type 'double' but the argument has type 'short'}}
printf ( " %f " , us ) ; // expected-warning{{format specifies type 'double' but the argument has type 'unsigned short'}}
// character literals
// In C language engineering practice, printing a character literal with %hhd or %d is common, but %hd may be misuse.
printf ( " %hhu " , ' a ' ) ; // no-warning
printf ( " %hhd " , ' a ' ) ; // no-warning
printf ( " %hd " , ' a ' ) ; // expected-warning{{format specifies type 'short' but the argument has type 'char'}}
printf ( " %hu " , ' a ' ) ; // expected-warning{{format specifies type 'unsigned short' but the argument has type 'char'}}
printf ( " %d " , ' a ' ) ; // no-warning
printf ( " %u " , ' a ' ) ; // no-warning
// pointers
printf ( " %s " , i ) ; // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
}