1 // RUN: %clang_cc1 -fsyntax-only -Wdynamic-class-memaccess -verify %s
2 
3 extern "C" void *memset(void *, int, unsigned);
4 extern "C" void *memmove(void *s1, const void *s2, unsigned n);
5 extern "C" void *memcpy(void *s1, const void *s2, unsigned n);
6 extern "C" void *memcmp(void *s1, const void *s2, unsigned n);
7 
8 
9 // Redeclare without the extern "C" to test that we still figure out that this
10 // is the "real" memset.
11 void *memset(void *, int, unsigned);
12 
13 // Several types that should not warn.
14 struct S1 {} s1;
15 struct S2 { int x; } s2;
16 struct S3 { float x, y; S1 s[4]; void (*f)(S1**); } s3;
17 
18 class C1 {
19   int x, y, z;
20 public:
foo()21   void foo() {}
22 } c1;
23 
24 struct X1 { virtual void f(); } x1, x1arr[2];
25 struct X2 : virtual S1 {} x2;
26 
27 struct ContainsDynamic { X1 dynamic; } contains_dynamic;
28 struct DeepContainsDynamic { ContainsDynamic m; } deep_contains_dynamic;
29 struct ContainsArrayDynamic { X1 dynamic[1]; } contains_array_dynamic;
30 struct ContainsPointerDynamic { X1 *dynamic; } contains_pointer_dynamic;
31 
test_warn()32 void test_warn() {
33   memset(&x1, 0, sizeof x1); // \
34       // expected-warning {{destination for this 'memset' call is a pointer to dynamic class}} \
35       // expected-note {{explicitly cast the pointer to silence this warning}}
36   memset(x1arr, 0, sizeof x1arr); // \
37       // expected-warning {{destination for this 'memset' call is a pointer to dynamic class}} \
38       // expected-note {{explicitly cast the pointer to silence this warning}}
39   memset((void*)x1arr, 0, sizeof x1arr);
40   memset(&x2, 0, sizeof x2); // \
41       // expected-warning {{destination for this 'memset' call is a pointer to dynamic class}} \
42       // expected-note {{explicitly cast the pointer to silence this warning}}
43 
44   memmove(&x1, 0, sizeof x1); // \
45       // expected-warning{{destination for this 'memmove' call is a pointer to dynamic class 'X1'; vtable pointer will be overwritten}} \
46       // expected-note {{explicitly cast the pointer to silence this warning}}
47   memmove(0, &x1, sizeof x1); // \
48       // expected-warning{{source of this 'memmove' call is a pointer to dynamic class 'X1'; vtable pointer will be moved}} \
49       // expected-note {{explicitly cast the pointer to silence this warning}}
50   memcpy(&x1, 0, sizeof x1); // \
51       // expected-warning{{destination for this 'memcpy' call is a pointer to dynamic class 'X1'; vtable pointer will be overwritten}} \
52       // expected-note {{explicitly cast the pointer to silence this warning}}
53   memcpy(0, &x1, sizeof x1); // \
54       // expected-warning{{source of this 'memcpy' call is a pointer to dynamic class 'X1'; vtable pointer will be copied}} \
55       // expected-note {{explicitly cast the pointer to silence this warning}}
56   memcmp(&x1, 0, sizeof x1); // \
57       // expected-warning{{first operand of this 'memcmp' call is a pointer to dynamic class 'X1'; vtable pointer will be compared}} \
58       // expected-note {{explicitly cast the pointer to silence this warning}}
59   memcmp(0, &x1, sizeof x1); // \
60       // expected-warning{{second operand of this 'memcmp' call is a pointer to dynamic class 'X1'; vtable pointer will be compared}} \
61       // expected-note {{explicitly cast the pointer to silence this warning}}
62 
63   __builtin_memset(&x1, 0, sizeof x1); // \
64       // expected-warning {{destination for this '__builtin_memset' call is a pointer to dynamic class}} \
65       // expected-note {{explicitly cast the pointer to silence this warning}}
66   __builtin_memset(&x2, 0, sizeof x2); // \
67       // expected-warning {{destination for this '__builtin_memset' call is a pointer to dynamic class}} \
68       // expected-note {{explicitly cast the pointer to silence this warning}}
69 
70   __builtin_memmove(&x1, 0, sizeof x1); // \
71       // expected-warning{{destination for this '__builtin_memmove' call is a pointer to dynamic class}} \
72       // expected-note {{explicitly cast the pointer to silence this warning}}
73   __builtin_memmove(0, &x1, sizeof x1); // \
74       // expected-warning{{source of this '__builtin_memmove' call is a pointer to dynamic class}} \
75       // expected-note {{explicitly cast the pointer to silence this warning}}
76   __builtin_memcpy(&x1, 0, sizeof x1); // \
77       // expected-warning{{destination for this '__builtin_memcpy' call is a pointer to dynamic class}} \
78       // expected-note {{explicitly cast the pointer to silence this warning}}
79   __builtin_memcpy(0, &x1, sizeof x1); // \
80       // expected-warning{{source of this '__builtin_memcpy' call is a pointer to dynamic class}} \
81       // expected-note {{explicitly cast the pointer to silence this warning}}
82 
83   __builtin___memset_chk(&x1, 0, sizeof x1, sizeof x1); //                    \
84       // expected-warning {{destination for this '__builtin___memset_chk' call is a pointer to dynamic class}} \
85       // expected-note {{explicitly cast the pointer to silence this warning}}
86   __builtin___memset_chk(&x2, 0, sizeof x2, sizeof x2); //                    \
87       // expected-warning {{destination for this '__builtin___memset_chk' call is a pointer to dynamic class}} \
88       // expected-note {{explicitly cast the pointer to silence this warning}}
89 
90   __builtin___memmove_chk(&x1, 0, sizeof x1, sizeof x1); //                   \
91       // expected-warning{{destination for this '__builtin___memmove_chk' call is a pointer to dynamic class}} \
92       // expected-note {{explicitly cast the pointer to silence this warning}}
93   __builtin___memmove_chk(0, &x1, sizeof x1, sizeof x1); //                   \
94       // expected-warning{{source of this '__builtin___memmove_chk' call is a pointer to dynamic class}} \
95       // expected-note {{explicitly cast the pointer to silence this warning}}
96   __builtin___memcpy_chk(&x1, 0, sizeof x1, sizeof x1); //                    \
97       // expected-warning{{destination for this '__builtin___memcpy_chk' call is a pointer to dynamic class}} \
98       // expected-note {{explicitly cast the pointer to silence this warning}}
99   __builtin___memcpy_chk(0, &x1, sizeof x1, sizeof x1); //                    \
100       // expected-warning{{source of this '__builtin___memcpy_chk' call is a pointer to dynamic class}} \
101       // expected-note {{explicitly cast the pointer to silence this warning}}
102 
103   // expected-warning@+2 {{destination for this 'memset' call is a pointer to class containing a dynamic class 'X1'}}
104   // expected-note@+1 {{explicitly cast the pointer to silence this warning}}
105   memset(&contains_dynamic, 0, sizeof(contains_dynamic));
106   // expected-warning@+2 {{destination for this 'memset' call is a pointer to class containing a dynamic class 'X1'}}
107   // expected-note@+1 {{explicitly cast the pointer to silence this warning}}
108   memset(&deep_contains_dynamic, 0, sizeof(deep_contains_dynamic));
109   // expected-warning@+2 {{destination for this 'memset' call is a pointer to class containing a dynamic class 'X1'}}
110   // expected-note@+1 {{explicitly cast the pointer to silence this warning}}
111   memset(&contains_array_dynamic, 0, sizeof(contains_array_dynamic));
112 }
113 
test_nowarn(void * void_ptr)114 void test_nowarn(void *void_ptr) {
115   int i, *iptr;
116   float y;
117   char c;
118 
119   memset(&i, 0, sizeof i);
120   memset(&iptr, 0, sizeof iptr);
121   memset(&y, 0, sizeof y);
122   memset(&c, 0, sizeof c);
123   memset(void_ptr, 0, 42);
124   memset(&s1, 0, sizeof s1);
125   memset(&s2, 0, sizeof s2);
126   memset(&s3, 0, sizeof s3);
127   memset(&c1, 0, sizeof c1);
128 
129   memset(&contains_pointer_dynamic, 0, sizeof(contains_pointer_dynamic));
130 
131   // Unevaluated code shouldn't warn.
132   (void)sizeof memset(&x1, 0, sizeof x1);
133 
134   // Dead code shouldn't warn.
135   if (false) memset(&x1, 0, sizeof x1);
136 }
137 
138 namespace N {
139   void *memset(void *, int, unsigned);
test_nowarn()140   void test_nowarn() {
141     N::memset(&x1, 0, sizeof x1);
142   }
143 }
144 
145 namespace recursive_class {
146 struct S {
147   S v;
148   // expected-error@-1{{field has incomplete type 'recursive_class::S'}}
149   // expected-note@-3{{definition of 'recursive_class::S' is not complete until the closing '}'}}
150 } a;
151 
main()152 int main() {
153   __builtin_memset(&a, 0, sizeof a);
154   return 0;
155 }
156 }
157