1 /* PR 71831 - __builtin_object_size poor results with no optimization
2    Verify that even without optimization __builtin_object_size returns
3    a meaningful result for a subset of simple expressins.  In cases
4    where the result could not easily be made to match the one obtained
5    with optimization the built-in was made to fail instead.  */
6 /* { dg-do run } */
7 /* { dg-options "-O0" } */
8 
9 static int nfails;
10 
11 #define TEST_FAILURE(line, obj, type, expect, result)		\
12   __builtin_printf ("FAIL: line %i: __builtin_object_size("	\
13 		    #obj ", %i) == %zu, got %zu\n",		\
14 		    line, type, expect, result), ++nfails
15 
16 #define bos(obj, type) __builtin_object_size (obj, type)
17 #define size(obj, n) ((size_t)n == X ? sizeof *obj : (size_t)n)
18 
19 #define test(expect, type, obj)						\
20   do {									\
21     if (bos (obj, type)	!= size (obj, expect))				\
22       TEST_FAILURE (__LINE__, obj, type, size (obj, expect), bos (obj, type)); \
23   } while (0)
24 
25 #define T(r0, r1, r2, r3, obj)			\
26   do {						\
27     test (r0, 0, obj);				\
28     test (r1, 1, obj);				\
29     test (r2, 2, obj);				\
30     test (r3, 3, obj);				\
31   } while (0)
32 
33 /* For convenience.  Substitute for 'sizeof object' in test cases where
34    the size can vary from target to target.  */
35 #define X  (size_t)0xdeadbeef
36 
37 /* __builtin_object_size checking results are inconsistent for equivalent
38    expressions (see bug 71831).  To avoid having duplicate the inconsistency
39    at -O0 the built-in simply fails.  The results hardcoded in this test
40    are those obtained with optimization (for easy comparison) but without
41    optimization the macros below turn them into expected failures .  */
42 #if __OPTIMIZE__
43 #  define F0(n)    n
44 #  define F1(n)    n
45 #  define F2(n)    n
46 #  define F3(n)    n
47 #else
48 #  define F0(n)   -1
49 #  define F1(n)   -1
50 #  define F2(n)    0
51 #  define F3(n)    0
52 #endif
53 
54 typedef __SIZE_TYPE__ size_t;
55 
56 extern char ax[];
57 char ax2[];               /* { dg-warning "assumed to have one element" } */
58 
59 extern char a0[0];
60 static char a1[1];
61 static char a2[2];
62 static char a9[9];
63 
64 #if __SIZEOF_SHORT__ == 4
65 extern short ia0[0];
66 static short ia1[1];
67 static short ia9[9];
68 #elif __SIZEOF_INT__ == 4
69 extern int ia0[0];
70 static int ia1[1];
71 static int ia9[9];
72 #elif __SIZEOF_LONG__ == 4
73 extern long ia0[0];
74 static long ia1[1];
75 static long ia9[9];
76 #endif
77 
78 static char a2x2[2][2];
79 static char a3x5[3][5];
80 
81 struct Sx { char n, a[]; } sx;
82 struct S0 { char n, a[0]; } s0;
83 struct S1 { char n, a[1]; } s1;
84 struct S2 { char n, a[2]; } s2;
85 struct S9 { char n, a[9]; } s9;
86 
87 struct S2x2 { char n, a[2][2]; } s2x2;
88 struct S3x5 { char n, a[3][5]; } s3x5;
89 
90 static __attribute__ ((noclone, noinline)) void
test_arrays()91 test_arrays ()
92 {
93   T (    -1,      -1,       0,       0,   ax);
94 
95   T (     0,       0,       0,       0,   a0);
96   T (     1,       1,       1,       1,   ax2);
97 
98   T (     1,       1,       1,       1,   a1);
99   T (     2,       2,       2,       2,   a2);
100   T (     9,       9,       9,       9,   a9);
101 
102   T (     0,       0,       0,       0,   a0);
103   T (     1,       1,       1,       1,   ax2);
104 
105   T (     0,       0,       0,       0,   ia0);
106   T (     4,       4,       4,       4,   ia1);
107   T (    36,      36,      36,      36,   ia9);
108 
109   /* Not all results for multidimensional arrays make sense (see
110      bug 77293).  The expected results below simply reflect those
111      obtained at -O2 (modulo the known limitations at -O1).  */
112   T (     4,       4,       4,       4,   a2x2);
113   T (     4,       4,       4,       4,   &a2x2[0]);
114   T (     4,       2,       4,       2,   &a2x2[0][0]);
115   T (     0,  F1  (0),      0,       0,   &a2x2 + 1);
116   T (     2,  F1 ( 2),      2,  F3 ( 2),  &a2x2[0] + 1);
117   T (     3,  F1 ( 1),      3,  F3 ( 3),  &a2x2[0][0] + 1);
118 
119   T (    15,      15,      15,      15,   a3x5);
120   T (    15,       5,      15,       5,   &a3x5[0][0] + 0);
121   T (    14,  F1 ( 4),     14,  F3 (14),  &a3x5[0][0] + 1);
122 
123   T (     1,       1,       1,       1,   a1 + 0);
124   T (     0,  F1  (0),      0,       0,   a1 + 1);
125   T (     0,  F1 ( 0),      0,       0,   &a1 + 1);
126   /* In the following the offset is out of bounds which makes
127      the expression undefined.  Still, verify that the returned
128      size is zero (and not some large number).  */
129   T (     0,  F1  (0),      0,       0,   a1 + 2);
130 
131   T (     2,       2,       2,       2,   a2 + 0);
132   T (     1,  F1 ( 1),      1, F3 ( 1),   a2 + 1);
133   T (     0,  F1 ( 0),      0,       0,   a2 + 2);
134 }
135 
136 static __attribute__ ((noclone, noinline)) void
test_structs(struct Sx * psx,struct S0 * ps0,struct S1 * ps1,struct S9 * ps9)137 test_structs (struct Sx *psx, struct S0 *ps0, struct S1 *ps1, struct S9 *ps9)
138 {
139   /* The expected size of a declared object with a flexible array member
140      is sizeof sx in all __builtin_object_size types.  */
141   T (     X,       X,       X,       X,   &sx);
142 
143   /* The expected size of an unknown object with a flexible array member
144      is unknown in all __builtin_object_size types.  */
145   T (    -1,      -1,       0,       0,   psx);
146 
147   /* The expected size of a flexible array member of a declared object
148      is zero.  */
149   T (     0,       0,       0,       0,   sx.a);
150 
151   /* The expected size of a flexible array member of an unknown object
152      is unknown.  */
153   T (    -1,      -1,       0,       0,   psx->a);
154 
155   /* The expected size of a declared object with a zero-length array member
156      is sizeof sx in all __builtin_object_size types.  */
157   T (     X,       X,       X,       X,   &s0);
158 
159   /* The expected size of an unknown object with a zero-length array member
160      is unknown in all __builtin_object_size types.  */
161   T (    -1,      -1,       0,       0,   ps0);
162 
163   /* The expected size of a zero-length array member of a declared object
164      is zero.  */
165   T (     0,       0,       0,       0,   s0.a);
166 
167   /* The expected size of a zero-length array member of an unknown object
168      is unknown.  */
169   T (    -1,      -1,       0,       0,   ps0->a);
170 
171   T (     X,       X,       X,       X,   &s1);
172   T (     1,       1,       1,       1,   s1.a);
173   T (     0,  F1 (0),       0,       0,   s1.a + 1);
174 
175   /* GCC treats arrays of all sizes that are the last member of a struct
176      as flexible array members.  */
177   T (    -1,      -1,       0,       0,   ps1);
178   T (    -1,      -1,       0,       0,   ps1->a);
179   T (    -1,      -1,       0,       0,   ps1->a + 1);
180 
181   T (     X,       X,       X,       X,   &s9);
182   T (     9,       9,       9,       9,   s9.a);
183   T (     9,       9,       9,       9,   s9.a + 0);
184   T (     8,  F1 ( 8),      8, F3 (  8),  s9.a + 1);
185   T (     7,  F1 ( 7),      7, F3 (  7),  s9.a + 2);
186   T (     0,  F1 ( 0),      0, F3 (  0),  s9.a + 9);
187 
188   /* The following make little sense but see bug 77301.  */
189   T (    -1,      -1,       0,       0,   ps9);
190   T (    -1,      -1,       0,       0,   ps9->a);
191   T (    -1,      -1,       0,       0,   ps9->a + 1);
192 }
193 
194 int
main()195 main()
196 {
197   test_arrays ();
198 
199   test_structs (&sx, &s0, &s1, &s9);
200 
201   if (nfails)
202     __builtin_abort ();
203 
204   return 0;
205 }
206