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