1 /* PR middle-end/87041 - -Wformat "reading through null pointer" on
2    unreachable code
3    Test to verify that the applicable subset of -Wformat-overflow warnings
4    are issued for the fprintf function.
5    { dg-do compile }
6    { dg-options "-O -Wformat -Wformat-overflow=1 -ftrack-macro-expansion=0" }
7    { dg-require-effective-target int32plus } */
8 
9 /* When debugging, define LINE to the line number of the test case to exercise
10    and avoid exercising any of the others.  The buffer and objsize macros
11    below make use of LINE to avoid warnings for other lines.  */
12 #ifndef LINE
13 # define LINE 0
14 #endif
15 
16 #define INT_MAX __INT_MAX__
17 
18 typedef __SIZE_TYPE__ size_t;
19 
20 #if !__cplusplus
21 typedef __WCHAR_TYPE__ wchar_t;
22 #endif
23 
24 typedef __WINT_TYPE__ wint_t;
25 
26 void sink (void*, ...);
27 
28 /* Declare as void* to work around bug 87775.  */
29 typedef void FILE;
30 
31 int dummy_fprintf (FILE*, const char*, ...);
32 
33 FILE *fp;
34 
35 const char chr_no_nul = 'a';
36 const char arr_no_nul[] = { 'a', 'b' };
37 
38 
39 /* Helper to expand function to either __builtin_f or dummy_f to
40    make debugging GCC easy.  */
41 #define T(...)							\
42   (((!LINE || LINE == __LINE__)					\
43     ? __builtin_fprintf : dummy_fprintf) (fp, __VA_ARGS__))
44 
45 /* Exercise the "%c" directive with constant arguments.  */
46 
test_fprintf_c_const(int width)47 void test_fprintf_c_const (int width)
48 {
49   /* Verify that a warning is issued for exceeding INT_MAX bytes and
50      not otherwise.  */
51   T ("%*c",  INT_MAX - 1, '1');
52   T ("%*c",  INT_MAX,     '1');
53   T ("X%*c", INT_MAX - 1, '1');
54   T ("X%*c", INT_MAX,     '1');   /* { dg-warning "directive output of \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
55 
56   T ("%*c%*c", INT_MAX - 1, '1', INT_MAX - 1, '2'); /* { dg-warning "directive output of \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
57 
58   T ("%*cX", INT_MAX - 2, '1');
59   T ("%*cX", INT_MAX - 1, '1');
60   T ("%*cX", INT_MAX,     '1');   /* { dg-warning "output of \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
61 
62   if (width < INT_MAX - 1)
63     width = INT_MAX - 1;
64   T ("%*cX", width, '1');
65   T ("%*cXY", width, '1');        /* { dg-warning ".XY. directive output of 2 bytes causes result to exceed .INT_MAX." } */
66 
67   /* Also exercise a non-constant format string.  The warning points
68      to the line where the format is declared (see bug 87773) so avoid
69      triggering that bug here.  */
70   const char *fmt = "%*cXYZ";  T (fmt, width, '1');            /* { dg-warning ".XYZ. directive output of 3 bytes causes result to exceed .INT_MAX." } */
71 }
72 
73 
74 /* Exercise the "%s" directive with constant arguments.  */
75 
test_fprintf_s_const(int width)76 void test_fprintf_s_const (int width)
77 {
78   const char *nulptr = 0;
79 
80   T ("%s", nulptr);               /* { dg-warning "\\\[-Wformat|-Wnonnull" } */
81   T ("%.0s", nulptr);             /* { dg-warning ".%.0s. directive argument is null" } */
82 
83   /* Verify no warning is issued for unreachable code.  */
84   if (nulptr)
85     T ("%s", nulptr);
86 
87   T ("%s", &chr_no_nul);          /* { dg-warning ".%s. directive argument is not a nul-terminated string" "pr88226" { xfail *-*-* } } */
88   T ("%s", arr_no_nul);           /* { dg-warning ".%s. directive argument is not a nul-terminated string" "pr88226" { xfail *-*-* } } */
89 
90   /* Verify that output in excess of INT_MAX bytes is diagnosed even
91      when the size of the destination object is unknown.  */
92   T ("%*s",  INT_MAX - 1, "");
93   T ("%*s",  INT_MAX,     "");
94   T ("X%*s", INT_MAX,     "");    /* { dg-warning "directive output of \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
95 
96   if (width < INT_MAX - 1)
97     width = INT_MAX - 1;
98   T ("%*sX", width, "1");
99   T ("%*sXY", width, "1");        /* { dg-warning ".XY. directive output of 2 bytes causes result to exceed .INT_MAX." } */
100 }
101 
102 
103 const wchar_t wchr_no_nul = L'a';
104 const wchar_t warr_no_nul[] = { L'a', L'b' };
105 
106 /* Exercise the "%s" directive with constant arguments.  */
107 
test_fprintf_ls_const(int width)108 void test_fprintf_ls_const (int width)
109 {
110   const wchar_t *nulptr = 0;
111 
112   T ("%ls", nulptr);              /* { dg-warning ".%ls. directive argument is null" } */
113   T ("%.0ls", nulptr);            /* { dg-warning ".%.0ls. directive argument is null" } */
114 
115   /* Verify no warning is issued for unreachable code.  */
116   if (nulptr)
117     T ("%ls", nulptr);
118 
119   T ("%ls", &wchr_no_nul);        /* { dg-warning ".%ls. directive argument is not a nul-terminated string" } */
120   T ("%ls", warr_no_nul);         /* { dg-warning ".%ls. directive argument is not a nul-terminated string" "pr88211" { xfail *-*-* } } */
121 
122   /* Verify that output in excess of INT_MAX bytes is diagnosed even
123      when the size of the destination object is unknown.  */
124   T ("%*ls",  INT_MAX - 1, L"");
125   T ("%*ls",  INT_MAX,     L"");
126   T ("X%*ls", INT_MAX,     L"");  /* { dg-warning "directive output of \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
127 
128   if (width < INT_MAX - 1)
129     width = INT_MAX - 1;
130   T ("%*lsX", width, L"1");
131   T ("%*lsXY", width, L"1");      /* { dg-warning ".XY. directive output of 2 bytes causes result to exceed .INT_MAX." } */
132 }
133