aboutsummaryrefslogtreecommitdiff
path: root/clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.cpp
blob: 62c945c7a2c242b33e935aa8412c549ef5478793 (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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.MemoryUnsafeCastChecker -verify %s

class Base { };
class Derived : public Base { };

template<typename Target, typename Source>
Target& downcast_ref(Source& source){
  [[clang::suppress]]
  return static_cast<Target&>(source);
}

template<typename Target, typename Source>
Target* downcast_ptr(Source* source){
  [[clang::suppress]]
  return static_cast<Target*>(source);
}

void test_pointers(Base *base) {
  Derived *derived_static = static_cast<Derived*>(base);
  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
  Derived *derived_reinterpret = reinterpret_cast<Derived*>(base);
  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
  Derived *derived_c = (Derived*)base;
  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
  Derived *derived_d = downcast_ptr<Derived, Base>(base);  // no warning
}

void test_non_pointers(Derived derived) {
  Base base_static = static_cast<Base>(derived);  // no warning
}

void test_refs(Base &base) {
  Derived &derived_static = static_cast<Derived&>(base);
  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
  Derived &derived_reinterpret = reinterpret_cast<Derived&>(base);
  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
  Derived &derived_c = (Derived&)base;
  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
  Derived &derived_d = downcast_ref<Derived, Base>(base);  // no warning
}

class BaseVirtual {
  virtual void virtual_base_function();
};

class DerivedVirtual : public BaseVirtual {
  void virtual_base_function() override { }
};

void test_dynamic_casts(BaseVirtual *base_ptr, BaseVirtual &base_ref) {
  DerivedVirtual *derived_dynamic_ptr = dynamic_cast<DerivedVirtual*>(base_ptr);
  // expected-warning@-1{{Unsafe cast from base type 'BaseVirtual' to derived type 'DerivedVirtual'}}
  DerivedVirtual &derived_dynamic_ref = dynamic_cast<DerivedVirtual&>(base_ref);
  // expected-warning@-1{{Unsafe cast from base type 'BaseVirtual' to derived type 'DerivedVirtual'}}
}

struct BaseStruct { };
struct DerivedStruct : BaseStruct { };

void test_struct_pointers(struct BaseStruct *base_struct) {
  struct DerivedStruct *derived_static = static_cast<struct DerivedStruct*>(base_struct);
  // expected-warning@-1{{Unsafe cast from base type 'BaseStruct' to derived type 'DerivedStruct'}}
  struct DerivedStruct *derived_reinterpret = reinterpret_cast<struct DerivedStruct*>(base_struct);
  // expected-warning@-1{{Unsafe cast from base type 'BaseStruct' to derived type 'DerivedStruct'}}
  struct DerivedStruct *derived_c = (struct DerivedStruct*)base_struct;
  // expected-warning@-1{{Unsafe cast from base type 'BaseStruct' to derived type 'DerivedStruct'}}
}

typedef struct BaseStruct BStruct;
typedef struct DerivedStruct DStruct;

void test_struct_refs(BStruct &base_struct) {
  DStruct &derived_static = static_cast<DStruct&>(base_struct);
  // expected-warning@-1{{Unsafe cast from base type 'BaseStruct' to derived type 'DerivedStruct'}}
  DStruct &derived_reinterpret = reinterpret_cast<DStruct&>(base_struct);
  // expected-warning@-1{{Unsafe cast from base type 'BaseStruct' to derived type 'DerivedStruct'}}
  DStruct &derived_c = (DStruct&)base_struct;
  // expected-warning@-1{{Unsafe cast from base type 'BaseStruct' to derived type 'DerivedStruct'}}
}

int counter = 0;
void test_recursive(BStruct &base_struct) {
  if (counter == 5)
    return;
  counter++;
  DStruct &derived_static = static_cast<DStruct&>(base_struct);
  // expected-warning@-1{{Unsafe cast from base type 'BaseStruct' to derived type 'DerivedStruct'}}
}

template<typename T>
class BaseTemplate { };

template<typename T>
class DerivedTemplate : public BaseTemplate<T> { };

void test_templates(BaseTemplate<int> *base, BaseTemplate<int> &base_ref) {
  DerivedTemplate<int> *derived_static = static_cast<DerivedTemplate<int>*>(base);
  // expected-warning@-1{{Unsafe cast from base type 'BaseTemplate' to derived type 'DerivedTemplate'}}
  DerivedTemplate<int> *derived_reinterpret = reinterpret_cast<DerivedTemplate<int>*>(base);
  // expected-warning@-1{{Unsafe cast from base type 'BaseTemplate' to derived type 'DerivedTemplate'}}
  DerivedTemplate<int> *derived_c = (DerivedTemplate<int>*)base;
  // expected-warning@-1{{Unsafe cast from base type 'BaseTemplate' to derived type 'DerivedTemplate'}}
  DerivedTemplate<int> &derived_static_ref = static_cast<DerivedTemplate<int>&>(base_ref);
  // expected-warning@-1{{Unsafe cast from base type 'BaseTemplate' to derived type 'DerivedTemplate'}}
  DerivedTemplate<int> &derived_reinterpret_ref = reinterpret_cast<DerivedTemplate<int>&>(base_ref);
  // expected-warning@-1{{Unsafe cast from base type 'BaseTemplate' to derived type 'DerivedTemplate'}}
  DerivedTemplate<int> &derived_c_ref = (DerivedTemplate<int>&)base_ref;
  // expected-warning@-1{{Unsafe cast from base type 'BaseTemplate' to derived type 'DerivedTemplate'}}
}

#define CAST_MACRO_STATIC(X,Y) (static_cast<Y>(X))
#define CAST_MACRO_REINTERPRET(X,Y) (reinterpret_cast<Y>(X))
#define CAST_MACRO_C(X,Y) ((Y)X)

void test_macro_static(Base *base, Derived *derived, Base &base_ref) {
  Derived *derived_static = CAST_MACRO_STATIC(base, Derived*);
  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
  Derived &derived_static_ref = CAST_MACRO_STATIC(base_ref, Derived&);
  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
  Base *base_static_same = CAST_MACRO_STATIC(base, Base*);  // no warning
  Base *base_static_upcast = CAST_MACRO_STATIC(derived, Base*);  // no warning
}

void test_macro_reinterpret(Base *base, Derived *derived, Base &base_ref) {
  Derived *derived_reinterpret = CAST_MACRO_REINTERPRET(base, Derived*);
  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
  Derived &derived_reinterpret_ref = CAST_MACRO_REINTERPRET(base_ref, Derived&);
  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
  Base *base_reinterpret_same = CAST_MACRO_REINTERPRET(base, Base*);  // no warning
  Base *base_reinterpret_upcast = CAST_MACRO_REINTERPRET(derived, Base*);  // no warning
}

void test_macro_c(Base *base, Derived *derived, Base &base_ref) {
  Derived *derived_c = CAST_MACRO_C(base, Derived*);
  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
  Derived &derived_c_ref = CAST_MACRO_C(base_ref, Derived&);
  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
  Base *base_c_same = CAST_MACRO_C(base, Base*);  // no warning
  Base *base_c_upcast = CAST_MACRO_C(derived, Base*);  // no warning
}

struct BaseStructCpp {
  int t;
  void increment() { t++; }
};
struct DerivedStructCpp : BaseStructCpp {
  void increment_t() {increment();}
};

void test_struct_cpp_pointers(struct BaseStructCpp *base_struct) {
  struct DerivedStructCpp *derived_static = static_cast<struct DerivedStructCpp*>(base_struct);
  // expected-warning@-1{{Unsafe cast from base type 'BaseStructCpp' to derived type 'DerivedStructCpp'}}
  struct DerivedStructCpp *derived_reinterpret = reinterpret_cast<struct DerivedStructCpp*>(base_struct);
  // expected-warning@-1{{Unsafe cast from base type 'BaseStructCpp' to derived type 'DerivedStructCpp'}}
  struct DerivedStructCpp *derived_c = (struct DerivedStructCpp*)base_struct;
  // expected-warning@-1{{Unsafe cast from base type 'BaseStructCpp' to derived type 'DerivedStructCpp'}}
}

typedef struct BaseStructCpp BStructCpp;
typedef struct DerivedStructCpp DStructCpp;

void test_struct_cpp_refs(BStructCpp &base_struct, DStructCpp &derived_struct) {
  DStructCpp &derived_static = static_cast<DStructCpp&>(base_struct);
  // expected-warning@-1{{Unsafe cast from base type 'BaseStructCpp' to derived type 'DerivedStructCpp'}}
  DStructCpp &derived_reinterpret = reinterpret_cast<DStructCpp&>(base_struct);
  // expected-warning@-1{{Unsafe cast from base type 'BaseStructCpp' to derived type 'DerivedStructCpp'}}
  DStructCpp &derived_c = (DStructCpp&)base_struct;
  // expected-warning@-1{{Unsafe cast from base type 'BaseStructCpp' to derived type 'DerivedStructCpp'}}
  BStructCpp &base = (BStructCpp&)derived_struct; // no warning
  BStructCpp &base_static = static_cast<BStructCpp&>(derived_struct); // no warning
  BStructCpp &base_reinterpret = reinterpret_cast<BStructCpp&>(derived_struct); // no warning
}

struct stack_st { };

#define STACK_OF(type) struct stack_st_##type

void test_stack(stack_st *base) {
  STACK_OF(void) *derived = (STACK_OF(void)*)base;
  // expected-warning@-1{{Unsafe cast from type 'stack_st' to an unrelated type 'stack_st_void'}}
}

class Parent { };
class Child1 : public Parent { };
class Child2 : public Parent { };

void test_common_parent(Child1 *c1, Child2 *c2) {
  Child2 *c2_cstyle = (Child2 *)c1;
  // expected-warning@-1{{Unsafe cast from type 'Child1' to an unrelated type 'Child2'}}
  Child2 *c2_reinterpret = reinterpret_cast<Child2 *>(c1);
  // expected-warning@-1{{Unsafe cast from type 'Child1' to an unrelated type 'Child2'}}
}

class Type1 { };
class Type2 { };

void test_unrelated_ref(Type1 &t1, Type2 &t2) {
  Type2 &t2_cstyle = (Type2 &)t1;
  // expected-warning@-1{{Unsafe cast from type 'Type1' to an unrelated type 'Type2'}}
  Type2 &t2_reinterpret = reinterpret_cast<Type2 &>(t1);
  // expected-warning@-1{{Unsafe cast from type 'Type1' to an unrelated type 'Type2'}}
  Type2 &t2_same = reinterpret_cast<Type2 &>(t2); // no warning
}


class VirtualClass1 {
  virtual void virtual_base_function();
};

class VirtualClass2 {
  void virtual_base_function();
};

void test_unrelated_virtual(VirtualClass1 &v1) {
  VirtualClass2 &v2 = dynamic_cast<VirtualClass2 &>(v1);
  // expected-warning@-1{{Unsafe cast from type 'VirtualClass1' to an unrelated type 'VirtualClass2'}}
}

struct StructA { };
struct StructB { };

typedef struct StructA StA;
typedef struct StructB StB;

void test_struct_unrelated_refs(StA &a, StB &b) {
  StB &b_reinterpret = reinterpret_cast<StB&>(a);
  // expected-warning@-1{{Unsafe cast from type 'StructA' to an unrelated type 'StructB'}}
  StB &b_c = (StB&)a;
  // expected-warning@-1{{Unsafe cast from type 'StructA' to an unrelated type 'StructB'}}
  StA &a_local = (StA&)b;
  // expected-warning@-1{{Unsafe cast from type 'StructB' to an unrelated type 'StructA'}}
  StA &a_reinterpret = reinterpret_cast<StA&>(b);
  // expected-warning@-1{{Unsafe cast from type 'StructB' to an unrelated type 'StructA'}}
  StA &a_same = (StA&)a; // no warning
}

template<typename T>
class DeferrableRefCounted {
public:
  void deref() const {
    auto this_to_T =  static_cast<const T*>(this); // no warning
  }
};

class SomeArrayClass : public DeferrableRefCounted<SomeArrayClass> { };

void test_this_to_template(SomeArrayClass *ptr) {
  ptr->deref();
};

template<typename WeakPtrFactoryType>
class CanMakeWeakPtrBase {
public:
  void initializeWeakPtrFactory() const {
    auto &this_to_T = static_cast<const WeakPtrFactoryType&>(*this);
  }
};

template<typename T>
using CanMakeWeakPtr = CanMakeWeakPtrBase<T>;

class EventLoop : public CanMakeWeakPtr<EventLoop> { };

void test_this_to_template_ref(EventLoop *ptr) {
  ptr->initializeWeakPtrFactory();
};