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 user-defined function declared attribute format printf.
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 #define ATTR(...) __attribute__ ((__VA_ARGS__))
18 
19 typedef __SIZE_TYPE__ size_t;
20 
21 #if !__cplusplus
22 typedef __WCHAR_TYPE__ wchar_t;
23 #endif
24 
25 typedef __WINT_TYPE__ wint_t;
26 
27 ATTR (format (printf, 2, 3)) void
28 user_print (char*, const char*, ...);
29 
30 ATTR (format (printf, 2, 3), nonnull) void
31 user_print_nonnull (char*, const char*, ...);
32 
33 ATTR (format (printf, 2, 3), nonnull (2)) void
34 user_print_nonnull_fmt (char*, const char*, ...);
35 
36 ATTR (format (printf, 2, 4), nonnull (3)) void
37 user_print_nonnull_other (char*, const char*, char*, ...);
38 
39 void dummy_print (char*, const char*, ...);
40 
41 const char chr_no_nul = 'a';
42 const char arr_no_nul[] = { 'a', 'b' };
43 
44 
45 /* Helper to expand function to either __builtin_f or dummy_f to
46    make debugging GCC easy.  */
47 #define T(...)							\
48   (((!LINE || LINE == __LINE__)					\
49     ? user_print : dummy_print) (0, __VA_ARGS__))
50 
51 /* Exercise the "%c" directive with constant arguments.  */
52 
test_user_print_format_string(void)53 void test_user_print_format_string (void)
54 {
55   char *null = 0;
56   /* Verify that no warning is issued for a null format string unless
57      the corresponding parameter is declared nonnull.  */
58   user_print (0, null);
59   user_print_nonnull ("x", "y");
60   user_print_nonnull ("x", null);   /* { dg-warning "\\\[-Wnonnull]" } */
61   user_print_nonnull_fmt (null, "x");
62   user_print_nonnull_fmt (0, null); /* { dg-warning "\\\[-Wnonnull]" } */
63   user_print_nonnull_other (null, "x", "y");
64   user_print_nonnull_other (null, "x", null);  /* { dg-warning "\\\[-Wnonnull]" } */
65 }
66 
67 
68 /* Exercise the "%c" directive with constant arguments.  */
69 
test_user_print_c_const(int width)70 void test_user_print_c_const (int width)
71 {
72   /* Verify that a warning is issued for exceeding INT_MAX bytes and
73      not otherwise.  */
74   T ("%*c",  INT_MAX - 1, '1');
75   T ("%*c",  INT_MAX,     '1');
76   T ("X%*c", INT_MAX - 1, '1');
77   T ("X%*c", INT_MAX,     '1');   /* { dg-warning "directive output of \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
78 
79   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." } */
80 
81   T ("%*cX", INT_MAX - 2, '1');
82   T ("%*cX", INT_MAX - 1, '1');
83   T ("%*cX", INT_MAX,     '1');   /* { dg-warning "output of \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
84 
85   if (width < INT_MAX - 1)
86     width = INT_MAX - 1;
87   T ("%*cX", width, '1');
88   T ("%*cXY", width, '1');        /* { dg-warning ".XY. directive output of 2 bytes causes result to exceed .INT_MAX." } */
89 
90   /* Also exercise a non-constant format string.  The warning points
91      to the line where the format is declared (see bug 87773) so avoid
92      triggering that bug here.  */
93   const char *fmt = "%*cXYZ";  T (fmt, width, '1');            /* { dg-warning ".XYZ. directive output of 3 bytes causes result to exceed .INT_MAX." } */
94 }
95 
96 
97 /* Exercise the "%s" directive with constant arguments.  */
98 
test_user_print_s_const(int width)99 void test_user_print_s_const (int width)
100 {
101   const char *null = 0;
102 
103   T ("%s", null);                 /* { dg-warning ".%s. directive argument is null" } */
104   T ("%.0s", null);               /* { dg-warning ".%.0s. directive argument is null" } */
105 
106   /* Verify no warning is issued for unreachable code.  */
107   if (null)
108     T ("%s", null);
109 
110   T ("%s", &chr_no_nul);          /* { dg-warning ".%s. directive argument is not a nul-terminated string" } */
111   T ("%s", arr_no_nul);           /* { dg-warning ".%s. directive argument is not a nul-terminated string" } */
112 
113   /* Verify that output in excess of INT_MAX bytes is diagnosed even
114      when the size of the destination object is unknown.  */
115   T ("%*s",  INT_MAX - 1, "");
116   T ("%*s",  INT_MAX,     "");
117   T ("X%*s", INT_MAX,     "");    /* { dg-warning "directive output of \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
118 
119   if (width < INT_MAX - 1)
120     width = INT_MAX - 1;
121   T ("%*sX", width, "1");
122   T ("%*sXY", width, "1");        /* { dg-warning ".XY. directive output of 2 bytes causes result to exceed .INT_MAX." } */
123 }
124 
125 
126 const wchar_t wchr_no_nul = L'a';
127 const wchar_t warr_no_nul[] = { L'a', L'b' };
128 
129 /* Exercise the "%s" directive with constant arguments.  */
130 
test_user_print_ls_const(int width)131 void test_user_print_ls_const (int width)
132 {
133   const wchar_t *null = 0;
134 
135   T ("%ls", null);                /* { dg-warning ".%ls. directive argument is null" } */
136   T ("%.0ls", null);              /* { dg-warning ".%.0ls. directive argument is null" } */
137 
138   /* Verify no warning is issued for unreachable code.  */
139   if (null)
140     T ("%ls", null);
141 
142   T ("%ls", &wchr_no_nul);        /* { dg-warning ".%ls. directive argument is not a nul-terminated string" } */
143   T ("%ls", warr_no_nul);         /* { dg-warning ".%ls. directive argument is not a nul-terminated string" "pr88211" { xfail *-*-* } } */
144 
145   /* Verify that output in excess of INT_MAX bytes is diagnosed even
146      when the size of the destination object is unknown.  */
147   T ("%*ls",  INT_MAX - 1, L"");
148   T ("%*ls",  INT_MAX,     L"");
149   T ("X%*ls", INT_MAX,     L"");  /* { dg-warning "directive output of \[0-9\]+ bytes causes result to exceed .INT_MAX." } */
150 
151   if (width < INT_MAX - 1)
152     width = INT_MAX - 1;
153   T ("%*lsX", width, L"1");
154   T ("%*lsXY", width, L"1");      /* { dg-warning ".XY. directive output of 2 bytes causes result to exceed .INT_MAX." } */
155 }
156