1 // RUN: %clang_cc1 %s -fsyntax-only -verify -fdata-sections -fcolor-diagnostics
2 
3 // Warn for any function that
4 //   * takes a pointer or a reference to an object (including "this" pointer),
5 //   * that was defined for aligned object,
6 //   * but is called with a pointer or reference to a less aligned object.
7 // Attributes on using declarations are ignored.
8 
9 typedef __attribute__((aligned(2))) int Aligned2Int;
10 typedef __attribute__((aligned(8))) int Aligned8Int;
11 
12 typedef __SIZE_TYPE__ size_t;
13 
14 // Normal function calls
f_takes_val(int i)15 void f_takes_val(int i) {}
f_takes_ptr(int * p)16 void f_takes_ptr(int *p) {}
f_takes_ref(int & p)17 void f_takes_ref(int &p) {}
18 
test0()19 void test0() {
20   Aligned2Int xwarn;
21   Aligned8Int xok;
22   f_takes_val(xwarn);
23   f_takes_ptr(&xwarn); // expected-warning {{passing 2-byte aligned argument to 4-byte aligned parameter 1 of 'f_takes_ptr' may result in an unaligned pointer access}}
24   f_takes_ref(xwarn);  // expected-warning {{passing 2-byte aligned argument to 4-byte aligned parameter 1 of 'f_takes_ref' may result in an unaligned pointer access}}
25   f_takes_val(xok);
26   f_takes_ptr(&xok);
27   f_takes_ref(xok);
28 }
29 
30 // Constructor expects to work on an 8 byte aligned type, but is called on a (potentially) 4 byte aligned object.
test1()31 void test1() {
32   struct StructAligned8 {
33     Aligned8Int Aligned8Member;
34     StructAligned8(int whatever) : Aligned8Member(whatever) {}
35   };
36   typedef __attribute__((aligned(4))) StructAligned8 TypedefAligned4;
37   using UsingAligned4 = __attribute__((aligned(4))) StructAligned8;
38 
39   StructAligned8 SA8(11);
40   TypedefAligned4 TA4(11); // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 'this' of 'StructAligned8' may result in an unaligned pointer access}}
41   UsingAligned4 UA4(11);
42 }
43 
44 // Same as above, should still trigger since passing by value is irrelevant
test1_byvalue()45 void test1_byvalue() {
46   struct StructAligned8 {
47     int __attribute__((aligned(8))) Aligned8Member;
48     int Irrelevant;
49     StructAligned8(Aligned8Int arg) : Aligned8Member(arg) {}
50   };
51   typedef __attribute__((aligned(4))) StructAligned8 TypedefAligned4;
52   using UsingAligned4 = __attribute__((aligned(4))) StructAligned8;
53 
54   Aligned8Int o{0};
55   StructAligned8 SA8(o);
56   TypedefAligned4 TA4(o); // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 'this' of 'StructAligned8' may result in an unaligned pointer access}}
57   UsingAligned4 UA4(o);
58 }
59 
60 // This example uses a function call trigger
test2()61 void test2() {
62   struct StructAligned8 {
63     int __attribute__((aligned(8))) Aligned8Member;
64     int Irrelevant;
65   };
66   auto assignment_function = [](StructAligned8 &S, Aligned8Int arg) {
67     S.Aligned8Member = arg;
68   };
69   typedef __attribute__((aligned(4))) StructAligned8 TypedefAligned4;
70   using UsingAligned4 = __attribute__((aligned(4))) StructAligned8;
71 
72   StructAligned8 SA8;
73   TypedefAligned4 TA4;          // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 'this' of 'StructAligned8' may result in an unaligned pointer access}}
74   assignment_function(TA4, 11); // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 1 of 'operator()' may result in an unaligned pointer access}}
75   UsingAligned4 UA4;
76   assignment_function(UA4, 11);
77 }
78 
79 // Same as above, but should not trigger as passed by value
test2_byvalue()80 void test2_byvalue() {
81   struct StructAligned8 {
82     int __attribute__((aligned(8))) Aligned8Member;
83     int Irrelevant;
84   };
85   auto assignment_function = [](StructAligned8 S, Aligned8Int arg) {
86     S.Aligned8Member = arg;
87   };
88   typedef __attribute__((aligned(4))) StructAligned8 TypedefAligned4;
89   using UsingAligned4 = __attribute__((aligned(4))) StructAligned8;
90 
91   Aligned8Int o{0};
92   StructAligned8 SA8;
93   TypedefAligned4 TA4; // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 'this' of 'StructAligned8' may result in an unaligned pointer access}}
94   assignment_function(TA4, o);
95   UsingAligned4 UA4;
96   assignment_function(UA4, o);
97 }
98 
test4()99 void test4() {
100   struct StructWithPackedMember {
101     int PackedMember __attribute__((packed));
102   } SWPM;
103 
104   // Explicitly taking the address of an unaligned member causes a warning
105   (void)&SWPM.PackedMember; // expected-warning {{taking address of packed member 'PackedMember' of class or structure 'StructWithPackedMember' may result in an unaligned pointer value}}
106 }
107 
108 // Aligned attribute on struct itself
test5()109 void test5() {
110   struct __attribute__((aligned(8))) StructAligned8 {
111     int Aligned8Member;
112     int Irrelevant;
113     StructAligned8(int i) : Aligned8Member(i) {}
114   };
115   typedef __attribute__((aligned(4))) StructAligned8 TypedefAligned4;
116   using UsingAligned4 = __attribute__((aligned(4))) StructAligned8;
117 
118   StructAligned8 SA8(11);
119   TypedefAligned4 TA4(11); // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 'this' of 'StructAligned8' may result in an unaligned pointer access}}
120   UsingAligned4 UA4(11);
121 }
122 
123 // Via function pointer
test6()124 void test6() {
125   struct __attribute__((aligned(8))) StructAligned8 {
126     int Aligned8Member;
127     StructAligned8(int i) : Aligned8Member(i) {}
128   };
129 
130   auto assignment_function_ref = [](StructAligned8 &S) {
131     S.Aligned8Member = 42;
132   };
133   auto assignment_function_ptr = [](StructAligned8 *S) {
134     S->Aligned8Member = 42;
135   };
136 
137   void (*RefFnPtr)(StructAligned8 &) = assignment_function_ref;
138   void (*PtrFnPtr)(StructAligned8 *) = assignment_function_ptr;
139 
140   typedef __attribute__((aligned(4))) StructAligned8 TypedefAligned4;
141   using UsingAligned4 = __attribute__((aligned(4))) StructAligned8;
142 
143   StructAligned8 SA8(11);
144   RefFnPtr(SA8);
145   PtrFnPtr(&SA8);
146   TypedefAligned4 TA4(11); // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 'this' of 'StructAligned8' may result in an unaligned pointer access}}
147   RefFnPtr(TA4);           // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 1 of 'RefFnPtr' may result in an unaligned pointer access}}
148   PtrFnPtr(&TA4);          // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 1 of 'PtrFnPtr' may result in an unaligned pointer access}}
149   UsingAligned4 UA4(11);
150   RefFnPtr(UA4);
151   PtrFnPtr(&UA4);
152 }
153 
154 // Member function
test7()155 void test7() {
156   struct __attribute__((aligned(8))) StructAligned8 {
157     int Aligned8Member;
158     StructAligned8(int i) : Aligned8Member(i) {}
159     void memberFnAssignment() {
160       Aligned8Member = 42;
161     }
162   };
163 
164   typedef __attribute__((aligned(4))) StructAligned8 TypedefAligned4;
165   using UsingAligned4 = __attribute__((aligned(4))) StructAligned8;
166 
167   StructAligned8 SA8(11);
168   SA8.memberFnAssignment();
169   TypedefAligned4 TA4(11);  // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 'this' of 'StructAligned8' may result in an unaligned pointer access}}
170   TA4.memberFnAssignment(); // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 'this' of 'memberFnAssignment' may result in an unaligned pointer access}}
171   UsingAligned4 UA4(11);
172   UA4.memberFnAssignment();
173 
174   // Check access through pointer
175   StructAligned8 *SA8ptr;
176   SA8ptr->memberFnAssignment();
177   TypedefAligned4 *TA4ptr;
178   TA4ptr->memberFnAssignment(); // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 'this' of 'memberFnAssignment' may result in an unaligned pointer access}}
179   UsingAligned4 *UA4ptr;
180   UA4ptr->memberFnAssignment();
181 }
182 
183 // Member binary and unary operator
test8()184 void test8() {
185   struct __attribute__((aligned(8))) StructAligned8 {
186     int Aligned8Member;
187     StructAligned8(int i) : Aligned8Member(i) {}
188     StructAligned8 operator+(StructAligned8 &other) {
189       return {other.Aligned8Member + Aligned8Member};
190     }
191     StructAligned8 operator-(StructAligned8 *other) {
192       return {other->Aligned8Member + Aligned8Member};
193     }
194     StructAligned8 &operator++() {
195       Aligned8Member++;
196       return *this;
197     }
198     StructAligned8 &operator--() {
199       Aligned8Member--;
200       return *this;
201     }
202   };
203 
204   typedef __attribute__((aligned(4))) StructAligned8 TypedefAligned4;
205   using UsingAligned4 = __attribute__((aligned(4))) StructAligned8;
206 
207   StructAligned8 SA8a(11);
208   StructAligned8 SA8b(11);
209   auto SA8c = SA8a + SA8b;
210   auto SA8d = SA8a - &SA8b;
211   ++SA8c;
212   --SA8d;
213   TypedefAligned4 TA8a(11);            // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 'this' of 'StructAligned8' may result in an unaligned pointer access}}
214   TypedefAligned4 TA8b(11);            // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 'this' of 'StructAligned8' may result in an unaligned pointer access}}
215   TypedefAligned4 TA8c = TA8a + TA8b;  // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 'this' of 'operator+' may result in an unaligned pointer access}}
216                                        // expected-warning@-1 {{passing 4-byte aligned argument to 8-byte aligned parameter 1 of 'operator+' may result in an unaligned pointer access}}
217                                        // expected-warning@-2 {{passing 4-byte aligned argument to 8-byte aligned parameter 'this' of 'StructAligned8' may result in an unaligned pointer access}}
218   TypedefAligned4 TA8d = TA8a - &TA8b; // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 'this' of 'operator-' may result in an unaligned pointer access}}
219                                        // expected-warning@-1 {{passing 4-byte aligned argument to 8-byte aligned parameter 1 of 'operator-' may result in an unaligned pointer access}}
220                                        // expected-warning@-2 {{passing 4-byte aligned argument to 8-byte aligned parameter 'this' of 'StructAligned8' may result in an unaligned pointer access}}
221   ++TA8d;                              // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 'this' of 'operator++' may result in an unaligned pointer access}}
222   --TA8c;                              // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 'this' of 'operator--' may result in an unaligned pointer access}}
223   UsingAligned4 UA8a(11);
224   UsingAligned4 UA8b(11);
225   auto UA8c = UA8a + UA8b;
226   auto UA8d = UA8a - &UA8b;
227   ++UA8c;
228   --UA8d;
229 
230   // Bonus
231   auto bonus1 = TA8a + SA8b;  // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 'this' of 'operator+' may result in an unaligned pointer access}}
232   auto bonus2 = SA8a + TA8b;  // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 1 of 'operator+' may result in an unaligned pointer access}}
233   auto bonus3 = TA8a - &SA8b; // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 'this' of 'operator-' may result in an unaligned pointer access}}
234   auto bonus4 = SA8a - &TA8b; // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 1 of 'operator-' may result in an unaligned pointer access}}
235 }
236 
237 // Static binary operator
238 struct __attribute__((aligned(8))) test9Struct {
239   int Aligned8Member;
test9Structtest9Struct240   test9Struct(int i) : Aligned8Member(i) {}
241 };
operator +(test9Struct & a,test9Struct & b)242 test9Struct operator+(test9Struct &a, test9Struct &b) {
243   return {a.Aligned8Member + b.Aligned8Member};
244 }
test9()245 void test9() {
246 
247   typedef __attribute__((aligned(4))) test9Struct TypedefAligned4;
248   using UsingAligned4 = __attribute__((aligned(4))) test9Struct;
249 
250   test9Struct SA8a(11);
251   test9Struct SA8b(11);
252   auto SA8c = SA8a + SA8b;
253   TypedefAligned4 TA8a(11); // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 'this' of 'test9Struct' may result in an unaligned pointer access}}
254   TypedefAligned4 TA8b(11); // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 'this' of 'test9Struct' may result in an unaligned pointer access}}
255   auto TA8c = TA8a + TA8b;  // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 1 of 'operator+' may result in an unaligned pointer access}}
256                             // expected-warning@-1 {{passing 4-byte aligned argument to 8-byte aligned parameter 2 of 'operator+' may result in an unaligned pointer access}}
257   UsingAligned4 UA8a(11);
258   UsingAligned4 UA8b(11);
259   auto UA8c = UA8a + UA8b;
260 
261   // Bonus
262   auto bonus1 = TA8a + SA8b; // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 1 of 'operator+' may result in an unaligned pointer access}}
263   auto bonus2 = SA8a + TA8b; // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 2 of 'operator+' may result in an unaligned pointer access}}
264 }
265 
266 // Operator new and placement new
test10()267 void test10() {
268   struct __attribute__((aligned(8))) StructAligned8 {
269     int Aligned8Member;
270     StructAligned8(int i) : Aligned8Member(i) {}
271     void *operator new(size_t count) { return (void *)0x123456; }
272     void *operator new(size_t count, void *p) { return p; }
273   };
274 
275   typedef __attribute__((aligned(4))) StructAligned8 TypedefAligned4;
276   using UsingAligned4 = __attribute__((aligned(4))) StructAligned8;
277 
278   auto *SA8ptr = new StructAligned8(11);
279   new (SA8ptr) StructAligned8(12);
280   auto *TA4ptr = new TypedefAligned4(11); // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 'this' of 'StructAligned8' may result in an unaligned pointer access}}
281   new (TA4ptr) TypedefAligned4(12);       // expected-warning {{passing 4-byte aligned argument to 8-byte aligned parameter 'this' of 'StructAligned8' may result in an unaligned pointer access}}
282   auto *UA4ptr = new UsingAligned4(11);
283   new (UA4ptr) UsingAligned4(12);
284 }
285 
testFunctionPointerArray(void (* fptr[10])(Aligned8Int *),Aligned2Int * src)286 void testFunctionPointerArray(void (*fptr[10])(Aligned8Int *), Aligned2Int* src) {
287   fptr[0](src); // expected-warning {{passing 2-byte aligned argument to 8-byte aligned parameter 1 may result in an unaligned pointer access}}
288 }
289