1 /* { dg-do compile } */
2 /* { dg-options "-O2 -Wformat -Wformat-truncation=1 -ftrack-macro-expansion=0" } */
3 
4 typedef struct
5 {
6   char a0[0];
7   /* Separate a0 from a1 to prevent the former from being substituted
8      for the latter and causing false positives.  */
9   int: 8;
10   char a1[1];
11   char a2[2];
12   char a3[3];
13   char a4[4];
14   char ax[];
15 } Arrays;
16 
17 char buffer[1024];
18 #define buffer(size) (buffer + sizeof buffer - size)
19 
value_range(int min,int max)20 static int value_range (int min, int max)
21 {
22   extern int value (void);
23   int val = value ();
24   return val < min || max < val ? min : val;
25 }
26 
27 #define R(min, max)  value_range (min, max)
28 
29 extern void sink (void*);
30 
31 /* Verify that calls to snprintf whose return value is unused are
32    diagnosed if certain or possible truncation is detected.  */
33 
34 #define T(size, ...) \
35   __builtin_snprintf (buffer (size), size, __VA_ARGS__), sink (buffer)
36 
test_int_retval_unused(void)37 void test_int_retval_unused (void)
38 {
39   T (2, "%i", 123);          /* { dg-warning "output truncated" } */
40   T (2, "%i", R (1, 99));    /* { dg-warning "output may be truncated" } */
41   T (2, "%i", R (10, 99));   /* { dg-warning "output truncated" } */
42   T (3, "%i%i", R (1, 99), R (1, 99));   /* { dg-warning "output may be truncated" } */
43 }
44 
test_string_retval_unused(const Arrays * ar)45 void test_string_retval_unused (const Arrays *ar)
46 {
47   /* At level 1 strings of unknown length are assumed to be empty so
48      the following is not diagnosed.  */
49   T (1, "%-s", ar->a0);
50   /* A one-byte array can only hold an empty string, so the following
51      isn't diagnosed.  */
52   T (1, "%-s", ar->a1);
53   /* Unlike the ar->a0 case above, at level 1, the length of an unknown
54      string that points to an array of known size is assumed to be the
55      size of the array minus 1.  */
56   T (1, "%-s", ar->a2);      /* { dg-warning "output may be truncated" } */
57   T (1, "%-s", ar->a3);      /* { dg-warning "output may be truncated" } */
58   T (1, "%-s", ar->a4);      /* { dg-warning "output may be truncated" } */
59   /* Same as the ar->a0 case above.  */
60   T (1, "%-s", ar->ax);
61 }
62 
63 
64 /* Verify that calls to snprintf whose return value is used are
65    diagnosed only if certain truncation is detected but not when
66    truncation is only possible but not certain.  */
67 
68 volatile int retval;
69 
70 #undef T
71 #define T(size, ...) \
72   retval = __builtin_snprintf (buffer (size), size, __VA_ARGS__)
73 
test_int_retval_used(void)74 void test_int_retval_used (void)
75 {
76   T (2, "%i", 123);          /* { dg-warning "output truncated" } */
77   T (2, "%i", R (1, 99));
78   T (2, "%i", R (10, 99));   /* { dg-warning "output truncated" } */
79   T (3, "%i%i", R (1, 99), R (1, 99));
80 }
81 
test_string_retval_used(const Arrays * ar)82 void test_string_retval_used (const Arrays *ar)
83 {
84   T (1, "%-s", ar->a0);
85   T (1, "%-s", ar->a1);
86   T (1, "%-s", ar->a2);
87   T (1, "%-s", ar->a3);
88   T (1, "%-s", ar->a4);
89   T (1, "%-s", "123");   /* { dg-warning "output truncated" } */
90 }
91