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
6 typedef __INTMAX_TYPE__ intmax_t;
7 typedef __UINTMAX_TYPE__ uintmax_t;
8 typedef int intptr_t;
9 typedef unsigned int uintptr_t;
10 typedef __WINT_TYPE__ wint_t;
11 typedef __SIZE_TYPE__ size_t;
12 typedef __SIZE_TYPE__ rsize_t;
13 typedef long ssize_t;
14 typedef __PTRDIFF_TYPE__ ptrdiff_t;
15 typedef unsigned int dev_t;
16 typedef int off_t;
17 typedef long clock_t;
18 typedef int time_t;
19 typedef long suseconds_t;
20 
21 // Other typedefs
22 typedef int int32_t;
23 typedef unsigned int uint32_t;
24 typedef long int64_t;
25 typedef unsigned long uint64_t;
26 
27 namespace std {
28 
29 template <class T>
30 struct allocator {};
31 
32 template <class T, class A = allocator<T>>
33 struct vector {};
34 
35 template <class F, class S>
36 struct pair {};
37 
38 }  // namespace std
39 
40 namespace base {
41 
42 class Pickle {};
43 
44 template <class T, class... Ts>
45 struct Tuple {
46   T value;
47 };
48 
49 }  // namespace base
50 
51 namespace IPC {
52 
53 template <class... T>
54 struct CheckedTuple {
55   typedef base::Tuple<T...> Tuple;
56 };
57 
58 template <class T>
59 struct ParamTraits {
WriteIPC::ParamTraits60   static void Write(base::Pickle*, const T&) {}
61 };
62 
63 template <class T>
WriteParam(base::Pickle * pickle,const T & value)64 void 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 
73 struct Data {
74   uint32_t value;
75   size_t size;
76 };
77 
78 template <>
79 struct IPC::ParamTraits<Data> {
WriteIPC::ParamTraits80   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 
87 template <class T>
88 struct Container {
89   T value;
90 };
91 
92 template <class T>
93 struct IPC::ParamTraits<Container<T>> {
WriteIPC::ParamTraits94   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 
111 template <class T, class... Ts>
112 struct MultiContainer {
113   T value;
114 };
115 
116 template <class T, class... Ts>
117 struct IPC::ParamTraits<MultiContainer<T, Ts...>> {
WriteIPC::ParamTraits118   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 
128 template <class T>
129 struct SomeClass {
WriteSomeClass130   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>
WriteExSomeClass140   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 
150 template <class T>
SomeWriteFunction(base::Pickle * pickle)151 void 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 
TestWriteParamInTemplates()167 void 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 
192 struct Empty {};
193 
194 IPC_TEST_MESSAGE(__COUNTER__, (bool, size_t, Empty, long)) // 2 ERRORs
195 
196 typedef std::vector<long> long1D;
197 typedef std::vector<long1D> long2D;
198 IPC_TEST_MESSAGE(__COUNTER__, (bool, long2D)) // ERROR
199 
200 IPC_TEST_MESSAGE(__COUNTER__, (char, short, std::pair<size_t, bool>)) // ERROR
201 
202 IPC_TEST_MESSAGE(__COUNTER__, (std::vector<std::vector<long&>&>&)) // ERROR
203 
204 
205 /* Check IPC::WriteParam() arguments. ERRORS: 30 */
206 
207 // ERRORS: 21
TestWriteParamArgument()208 void 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 
282 struct Provider {
283   typedef unsigned int flags;
284 
get_shortProvider285   short get_short() const { return 0; }
get_uint64Provider286   uint64_t get_uint64() const { return 0; }
get_longProvider287   long get_long() const { return 0; }
get_uintProvider288   unsigned int get_uint() const { return 0; }
get_flagsProvider289   flags get_flags() const { return 0; }
get_sizeProvider290   size_t get_size() const { return 0; }
291 
get_sizesProvider292   const std::vector<size_t>& get_sizes() const { return sizes_data; }
get_uint64sProvider293   const std::vector<uint64_t>& get_uint64s() const { return uint64s_data; }
294 
295   template <class T>
getProvider296   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
TestWriteParamMemberArgument()309 void 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