summaryrefslogtreecommitdiff
path: root/test/SemaCXX/warn-bad-memaccess.cpp
blob: e86610ab64d9636705e2631e2f966069df0607a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// RUN: %clang_cc1 -fsyntax-only -Wdynamic-class-memaccess -verify %s

extern "C" void *memset(void *, int, unsigned);
extern "C" void *memmove(void *s1, const void *s2, unsigned n);
extern "C" void *memcpy(void *s1, const void *s2, unsigned n);
extern "C" void *memcmp(void *s1, const void *s2, unsigned n);


// Redeclare without the extern "C" to test that we still figure out that this
// is the "real" memset.
void *memset(void *, int, unsigned);

// Several types that should not warn.
struct S1 {} s1;
struct S2 { int x; } s2;
struct S3 { float x, y; S1 s[4]; void (*f)(S1**); } s3;

class C1 {
  int x, y, z;
public:
  void foo() {}
} c1;

struct X1 { virtual void f(); } x1;
struct X2 : virtual S1 {} x2;

struct ContainsDynamic { X1 dynamic; } contains_dynamic;
struct DeepContainsDynamic { ContainsDynamic m; } deep_contains_dynamic;
struct ContainsArrayDynamic { X1 dynamic[1]; } contains_array_dynamic;
struct ContainsPointerDynamic { X1 *dynamic; } contains_pointer_dynamic;

void test_warn() {
  memset(&x1, 0, sizeof x1); // \
      // expected-warning {{destination for this 'memset' call is a pointer to dynamic class}} \
      // expected-note {{explicitly cast the pointer to silence this warning}}
  memset(&x2, 0, sizeof x2); // \
      // expected-warning {{destination for this 'memset' call is a pointer to dynamic class}} \
      // expected-note {{explicitly cast the pointer to silence this warning}}

  memmove(&x1, 0, sizeof x1); // \
      // expected-warning{{destination for this 'memmove' call is a pointer to dynamic class 'X1'; vtable pointer will be overwritten}} \
      // expected-note {{explicitly cast the pointer to silence this warning}}
  memmove(0, &x1, sizeof x1); // \
      // expected-warning{{source of this 'memmove' call is a pointer to dynamic class 'X1'; vtable pointer will be moved}} \
      // expected-note {{explicitly cast the pointer to silence this warning}}
  memcpy(&x1, 0, sizeof x1); // \
      // expected-warning{{destination for this 'memcpy' call is a pointer to dynamic class 'X1'; vtable pointer will be overwritten}} \
      // expected-note {{explicitly cast the pointer to silence this warning}}
  memcpy(0, &x1, sizeof x1); // \
      // expected-warning{{source of this 'memcpy' call is a pointer to dynamic class 'X1'; vtable pointer will be copied}} \
      // expected-note {{explicitly cast the pointer to silence this warning}}
  memcmp(&x1, 0, sizeof x1); // \
      // expected-warning{{first operand of this 'memcmp' call is a pointer to dynamic class 'X1'; vtable pointer will be compared}} \
      // expected-note {{explicitly cast the pointer to silence this warning}}
  memcmp(0, &x1, sizeof x1); // \
      // expected-warning{{second operand of this 'memcmp' call is a pointer to dynamic class 'X1'; vtable pointer will be compared}} \
      // expected-note {{explicitly cast the pointer to silence this warning}}

  __builtin_memset(&x1, 0, sizeof x1); // \
      // expected-warning {{destination for this '__builtin_memset' call is a pointer to dynamic class}} \
      // expected-note {{explicitly cast the pointer to silence this warning}}
  __builtin_memset(&x2, 0, sizeof x2); // \
      // expected-warning {{destination for this '__builtin_memset' call is a pointer to dynamic class}} \
      // expected-note {{explicitly cast the pointer to silence this warning}}

  __builtin_memmove(&x1, 0, sizeof x1); // \
      // expected-warning{{destination for this '__builtin_memmove' call is a pointer to dynamic class}} \
      // expected-note {{explicitly cast the pointer to silence this warning}}
  __builtin_memmove(0, &x1, sizeof x1); // \
      // expected-warning{{source of this '__builtin_memmove' call is a pointer to dynamic class}} \
      // expected-note {{explicitly cast the pointer to silence this warning}}
  __builtin_memcpy(&x1, 0, sizeof x1); // \
      // expected-warning{{destination for this '__builtin_memcpy' call is a pointer to dynamic class}} \
      // expected-note {{explicitly cast the pointer to silence this warning}}
  __builtin_memcpy(0, &x1, sizeof x1); // \
      // expected-warning{{source of this '__builtin_memcpy' call is a pointer to dynamic class}} \
      // expected-note {{explicitly cast the pointer to silence this warning}}

  __builtin___memset_chk(&x1, 0, sizeof x1, sizeof x1); //                    \
      // expected-warning {{destination for this '__builtin___memset_chk' call is a pointer to dynamic class}} \
      // expected-note {{explicitly cast the pointer to silence this warning}}
  __builtin___memset_chk(&x2, 0, sizeof x2, sizeof x2); //                    \
      // expected-warning {{destination for this '__builtin___memset_chk' call is a pointer to dynamic class}} \
      // expected-note {{explicitly cast the pointer to silence this warning}}

  __builtin___memmove_chk(&x1, 0, sizeof x1, sizeof x1); //                   \
      // expected-warning{{destination for this '__builtin___memmove_chk' call is a pointer to dynamic class}} \
      // expected-note {{explicitly cast the pointer to silence this warning}}
  __builtin___memmove_chk(0, &x1, sizeof x1, sizeof x1); //                   \
      // expected-warning{{source of this '__builtin___memmove_chk' call is a pointer to dynamic class}} \
      // expected-note {{explicitly cast the pointer to silence this warning}}
  __builtin___memcpy_chk(&x1, 0, sizeof x1, sizeof x1); //                    \
      // expected-warning{{destination for this '__builtin___memcpy_chk' call is a pointer to dynamic class}} \
      // expected-note {{explicitly cast the pointer to silence this warning}}
  __builtin___memcpy_chk(0, &x1, sizeof x1, sizeof x1); //                    \
      // expected-warning{{source of this '__builtin___memcpy_chk' call is a pointer to dynamic class}} \
      // expected-note {{explicitly cast the pointer to silence this warning}}

  // expected-warning@+2 {{destination for this 'memset' call is a pointer to class containing a dynamic class 'X1'}}
  // expected-note@+1 {{explicitly cast the pointer to silence this warning}}
  memset(&contains_dynamic, 0, sizeof(contains_dynamic));
  // expected-warning@+2 {{destination for this 'memset' call is a pointer to class containing a dynamic class 'X1'}}
  // expected-note@+1 {{explicitly cast the pointer to silence this warning}}
  memset(&deep_contains_dynamic, 0, sizeof(deep_contains_dynamic));
  // expected-warning@+2 {{destination for this 'memset' call is a pointer to class containing a dynamic class 'X1'}}
  // expected-note@+1 {{explicitly cast the pointer to silence this warning}}
  memset(&contains_array_dynamic, 0, sizeof(contains_array_dynamic));
}

void test_nowarn(void *void_ptr) {
  int i, *iptr;
  float y;
  char c;

  memset(&i, 0, sizeof i);
  memset(&iptr, 0, sizeof iptr);
  memset(&y, 0, sizeof y);
  memset(&c, 0, sizeof c);
  memset(void_ptr, 0, 42);
  memset(&s1, 0, sizeof s1);
  memset(&s2, 0, sizeof s2);
  memset(&s3, 0, sizeof s3);
  memset(&c1, 0, sizeof c1);

  memset(&contains_pointer_dynamic, 0, sizeof(contains_pointer_dynamic));

  // Unevaluated code shouldn't warn.
  (void)sizeof memset(&x1, 0, sizeof x1);

  // Dead code shouldn't warn.
  if (false) memset(&x1, 0, sizeof x1);
}

namespace N {
  void *memset(void *, int, unsigned);
  void test_nowarn() {
    N::memset(&x1, 0, sizeof x1);
  }
}