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