1// Copyright (c) 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Blacklisted typedefs
6typedef __INTMAX_TYPE__ intmax_t;
7typedef __UINTMAX_TYPE__ uintmax_t;
8typedef int intptr_t;
9typedef unsigned int uintptr_t;
10typedef __WINT_TYPE__ wint_t;
11typedef __SIZE_TYPE__ size_t;
12typedef __SIZE_TYPE__ rsize_t;
13typedef long ssize_t;
14typedef __PTRDIFF_TYPE__ ptrdiff_t;
15typedef unsigned int dev_t;
16typedef int off_t;
17typedef long clock_t;
18typedef int time_t;
19typedef long suseconds_t;
20
21// Other typedefs
22typedef int int32_t;
23typedef unsigned int uint32_t;
24typedef long int64_t;
25typedef unsigned long uint64_t;
26
27namespace std {
28
29template <class T>
30struct allocator {};
31
32template <class T, class A = allocator<T>>
33struct vector {};
34
35template <class F, class S>
36struct pair {};
37
38}  // namespace std
39
40namespace base {
41
42class Pickle {};
43
44template <class T, class... Ts>
45struct Tuple {
46  T value;
47};
48
49}  // namespace base
50
51namespace IPC {
52
53template <class... T>
54struct CheckedTuple {
55  typedef base::Tuple<T...> Tuple;
56};
57
58template <class T>
59struct ParamTraits {
60  static void Write(base::Pickle*, const T&) {}
61};
62
63template <class T>
64void WriteParam(base::Pickle* pickle, const T& value) {
65  ParamTraits<T>::Write(pickle, value);
66}
67
68}  // namespace IPC
69
70
71/* Test IPC::WriteParam() usage in templates. ERRORS: 6 */
72
73struct Data {
74  uint32_t value;
75  size_t size;
76};
77
78template <>
79struct IPC::ParamTraits<Data> {
80  static void Write(base::Pickle* pickle, const Data& p) {
81    // OK: WriteParam() called in explicit specialization
82    WriteParam(pickle, p.value); // OK
83    WriteParam(pickle, p.size); // ERROR
84  }
85};
86
87template <class T>
88struct Container {
89  T value;
90};
91
92template <class T>
93struct IPC::ParamTraits<Container<T>> {
94  static void Write(base::Pickle* pickle, const Container<T>& container) {
95    // NOT CHECKED: T is not explicitly referenced
96    IPC::WriteParam(pickle, container.value); // NOT CHECKED
97    WriteParam(pickle, container.value); // NOT CHECKED
98
99    // NOT CHECKED: T explicitly referenced
100    IPC::WriteParam<T>(pickle, container.value); // NOT CHECKED
101    WriteParam<T>(pickle, container.value); // NOT CHECKED
102
103    // OK: explicit cast to non-dependent allowed type
104    WriteParam(pickle, static_cast<uint32_t>(container.value)); // OK
105
106    // ERROR: explicit cast to non-dependent banned type
107    WriteParam(pickle, static_cast<long>(container.value)); // ERROR
108  }
109};
110
111template <class T, class... Ts>
112struct MultiContainer {
113  T value;
114};
115
116template <class T, class... Ts>
117struct IPC::ParamTraits<MultiContainer<T, Ts...>> {
118  static void Write(base::Pickle* pickle,
119                    const MultiContainer<T, Ts...>& container) {
120    // NOT CHECKED: template argument explicitly referenced
121    bool helper[] = {
122        (WriteParam<Ts>(pickle, container.value), true)... // NOT CHECKED
123    };
124    (void)helper;
125  }
126};
127
128template <class T>
129struct SomeClass {
130  static void Write(base::Pickle* pickle) {
131    // NOT CHECKED: WriteParam() calls on dependent types
132    IPC::WriteParam(pickle, T(0)); // NOT CHECKED
133
134    // Non-dependent types are checked
135    IPC::WriteParam(pickle, size_t(0)); // ERROR
136    IPC::WriteParam(pickle, uint64_t(0)); // OK
137  }
138
139  template <class U>
140  static void WriteEx(base::Pickle* pickle) {
141    // NOT CHECKED: WriteParam() calls on dependent types
142    IPC::WriteParam(pickle, U(0)); // NOT CHECKED
143
144    // Non-dependent types are checked
145    IPC::WriteParam(pickle, time_t(0)); // ERROR
146    IPC::WriteParam(pickle, uint32_t(0)); // OK
147  }
148};
149
150template <class T>
151void SomeWriteFunction(base::Pickle* pickle) {
152  // NOT CHECKED: WriteParam() calls on dependent types
153  IPC::WriteParam(pickle, T(0)); // NOT CHECKED
154
155  // Non-dependent types are checked
156  IPC::WriteParam(pickle, long(0)); // ERROR
157  IPC::WriteParam(pickle, char(0)); // OK
158
159  [&](){
160    IPC::WriteParam(pickle, T(0)); // NOT CHECKED
161
162    IPC::WriteParam(pickle, clock_t(0)); // ERROR
163    IPC::WriteParam(pickle, int64_t(0)); // OK
164  }();
165}
166
167void TestWriteParamInTemplates() {
168  // These specializations call WriteParam() on various banned types, either
169  // because they were specified directly (long) or because non-blacklisted
170  // typedef (uint64_t) was stripped down to its underlying type, which is
171  // blacklisted when used as is (unsigned long).
172  // However, since it's hard (if not impossible) to check specializations
173  // properly, we're simply not checking them.
174  SomeClass<long>::Write(nullptr);
175  SomeClass<long>::WriteEx<uint64_t>(nullptr);
176  SomeWriteFunction<uint64_t>(nullptr);
177}
178
179
180/* Test IPC::CheckedTuple. ERRORS: 5 */
181
182#define IPC_TUPLE(...) IPC::CheckedTuple<__VA_ARGS__>::Tuple
183
184#define IPC_MESSAGE_DECL(name, id, in_tuple) \
185  struct name ## Meta_ ## id { \
186    using InTuple = in_tuple; \
187  };
188
189#define IPC_TEST_MESSAGE(id, in) \
190  IPC_MESSAGE_DECL(TestMessage, id, IPC_TUPLE in)
191
192struct Empty {};
193
194IPC_TEST_MESSAGE(__COUNTER__, (bool, size_t, Empty, long)) // 2 ERRORs
195
196typedef std::vector<long> long1D;
197typedef std::vector<long1D> long2D;
198IPC_TEST_MESSAGE(__COUNTER__, (bool, long2D)) // ERROR
199
200IPC_TEST_MESSAGE(__COUNTER__, (char, short, std::pair<size_t, bool>)) // ERROR
201
202IPC_TEST_MESSAGE(__COUNTER__, (std::vector<std::vector<long&>&>&)) // ERROR
203
204
205/* Check IPC::WriteParam() arguments. ERRORS: 30 */
206
207// ERRORS: 21
208void TestWriteParamArgument() {
209  #define CALL_WRITEPARAM(Type) \
210    { \
211      Type p; \
212      IPC::WriteParam(nullptr, p); \
213    }
214
215  // ERROR: blacklisted types / typedefs
216  CALL_WRITEPARAM(long) // ERROR
217  CALL_WRITEPARAM(unsigned long) // ERROR
218  CALL_WRITEPARAM(intmax_t) // ERROR
219  CALL_WRITEPARAM(uintmax_t) // ERROR
220  CALL_WRITEPARAM(intptr_t) // ERROR
221  CALL_WRITEPARAM(uintptr_t) // ERROR
222  CALL_WRITEPARAM(wint_t) // ERROR
223  CALL_WRITEPARAM(size_t) // ERROR
224  CALL_WRITEPARAM(rsize_t) // ERROR
225  CALL_WRITEPARAM(ssize_t) // ERROR
226  CALL_WRITEPARAM(ptrdiff_t) // ERROR
227  CALL_WRITEPARAM(dev_t) // ERROR
228  CALL_WRITEPARAM(off_t) // ERROR
229  CALL_WRITEPARAM(clock_t) // ERROR
230  CALL_WRITEPARAM(time_t) // ERROR
231  CALL_WRITEPARAM(suseconds_t) // ERROR
232
233  // ERROR: typedef to blacklisted typedef
234  typedef size_t my_size;
235  CALL_WRITEPARAM(my_size) // ERROR
236
237  // ERROR: expression ends up with type "unsigned long"
238  {
239    uint64_t p = 0;
240    IPC::WriteParam(nullptr, p + 1); // ERROR
241  }
242
243  // ERROR: long chain of typedefs, ends up with blacklisted typedef
244  {
245    typedef size_t my_size_base;
246    typedef const my_size_base my_size;
247    typedef my_size& my_size_ref;
248    my_size_ref p = 0;
249    IPC::WriteParam(nullptr, p); // ERROR
250  }
251
252  // ERROR: template specialization references blacklisted type
253  CALL_WRITEPARAM(std::vector<long>) // ERROR
254  CALL_WRITEPARAM(std::vector<size_t>) // ERROR
255
256  // OK: typedef to blacklisted type
257  typedef long my_long;
258  CALL_WRITEPARAM(my_long) // OK
259
260  // OK: other types / typedefs
261  CALL_WRITEPARAM(char) // OK
262  CALL_WRITEPARAM(int) // OK
263  CALL_WRITEPARAM(uint32_t) // OK
264  CALL_WRITEPARAM(int64_t) // OK
265
266  // OK: long chain of typedefs, ends up with non-blacklisted typedef
267  {
268    typedef uint32_t my_int_base;
269    typedef const my_int_base my_int;
270    typedef my_int& my_int_ref;
271    my_int_ref p = 0;
272    IPC::WriteParam(nullptr, p); // OK
273  }
274
275  // OK: template specialization references non-blacklisted type
276  CALL_WRITEPARAM(std::vector<char>) // OK
277  CALL_WRITEPARAM(std::vector<my_long>) // OK
278
279  #undef CALL_WRITEPARAM
280}
281
282struct Provider {
283  typedef unsigned int flags;
284
285  short get_short() const { return 0; }
286  uint64_t get_uint64() const { return 0; }
287  long get_long() const { return 0; }
288  unsigned int get_uint() const { return 0; }
289  flags get_flags() const { return 0; }
290  size_t get_size() const { return 0; }
291
292  const std::vector<size_t>& get_sizes() const { return sizes_data; }
293  const std::vector<uint64_t>& get_uint64s() const { return uint64s_data; }
294
295  template <class T>
296  T get() const { return T(); }
297
298  short short_data;
299  unsigned int uint_data;
300  flags flags_data;
301  long long_data;
302  size_t size_data;
303  uint64_t uint64_data;
304  std::vector<size_t> sizes_data;
305  std::vector<uint64_t> uint64s_data;
306};
307
308// ERRORS: 9
309void TestWriteParamMemberArgument() {
310  Provider p;
311
312  IPC::WriteParam(nullptr, p.get<short>()); // OK
313  IPC::WriteParam(nullptr, p.get_short()); // OK
314  IPC::WriteParam(nullptr, p.short_data); // OK
315
316  IPC::WriteParam(nullptr, p.get<unsigned int>()); // OK
317  IPC::WriteParam(nullptr, p.get_uint()); // OK
318  IPC::WriteParam(nullptr, p.uint_data); // OK
319
320  IPC::WriteParam(nullptr, p.get<Provider::flags>()); // OK
321  IPC::WriteParam(nullptr, p.get_flags()); // OK
322  IPC::WriteParam(nullptr, p.flags_data); // OK
323
324  IPC::WriteParam(nullptr, p.get<long>()); // ERROR
325  IPC::WriteParam(nullptr, p.get_long()); // ERROR
326  IPC::WriteParam(nullptr, p.long_data); // ERROR
327
328  // This one is flaky and depends on whether size_t is typedefed to a
329  // blacklisted type (unsigned long).
330  //IPC::WriteParam(nullptr, p.get<size_t>()); // ERROR
331  IPC::WriteParam(nullptr, p.get_size()); // ERROR
332  IPC::WriteParam(nullptr, p.size_data); // ERROR
333
334  // Information about uint64_t gets lost, and plugin sees WriteParam()
335  // call on unsigned long, which is blacklisted.
336  IPC::WriteParam(nullptr, p.get<uint64_t>()); // ERROR
337  IPC::WriteParam(nullptr, p.get_uint64()); // OK
338  IPC::WriteParam(nullptr, p.uint64_data); // OK
339
340  // Same thing here, WriteParam() sees vector<unsigned long>, and denies it.
341  IPC::WriteParam(nullptr, p.get<std::vector<uint64_t>>()); // ERROR
342  IPC::WriteParam(nullptr, p.get_uint64s()); // OK
343  IPC::WriteParam(nullptr, p.uint64s_data); // OK
344
345  // This one is flaky and depends on whether size_t is typedefed to a
346  // blacklisted type (unsigned long).
347  //IPC::WriteParam(nullptr, p.get<std::vector<size_t>>());
348  IPC::WriteParam(nullptr, p.get_sizes()); // ERROR
349  IPC::WriteParam(nullptr, p.sizes_data); // ERROR
350}
351
352
353/* ERRORS: 41 */
354