OLD | NEW |
| (Empty) |
1 // Copyright 2013 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 #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_ | |
6 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_ | |
7 | |
8 #include <new> | |
9 #include <string> | |
10 #include <type_traits> | |
11 #include <vector> | |
12 | |
13 #include "mojo/public/cpp/bindings/lib/bindings_internal.h" | |
14 #include "mojo/public/cpp/bindings/lib/bindings_serialization.h" | |
15 #include "mojo/public/cpp/bindings/lib/bounds_checker.h" | |
16 #include "mojo/public/cpp/bindings/lib/buffer.h" | |
17 #include "mojo/public/cpp/bindings/lib/map_data_internal.h" | |
18 #include "mojo/public/cpp/bindings/lib/validate_params.h" | |
19 #include "mojo/public/cpp/bindings/lib/validation_errors.h" | |
20 #include "mojo/public/cpp/environment/logging.h" | |
21 | |
22 namespace mojo { | |
23 template <typename T> | |
24 class Array; | |
25 class String; | |
26 | |
27 namespace internal { | |
28 | |
29 // std::numeric_limits<uint32_t>::max() is not a compile-time constant (until | |
30 // C++11). | |
31 const uint32_t kMaxUint32 = 0xFFFFFFFF; | |
32 | |
33 // TODO(vardhan): Get rid of the following 2 functions. | |
34 std::string MakeMessageWithArrayIndex(const char* message, | |
35 size_t size, | |
36 size_t index); | |
37 | |
38 std::string MakeMessageWithExpectedArraySize(const char* message, | |
39 size_t size, | |
40 size_t expected_size); | |
41 | |
42 template <typename T> | |
43 struct ArrayDataTraits { | |
44 typedef T StorageType; | |
45 typedef T& Ref; | |
46 typedef T const& ConstRef; | |
47 | |
48 static const uint32_t kMaxNumElements = | |
49 (kMaxUint32 - sizeof(ArrayHeader)) / sizeof(StorageType); | |
50 | |
51 static uint32_t GetStorageSize(uint32_t num_elements) { | |
52 MOJO_DCHECK(num_elements <= kMaxNumElements); | |
53 return sizeof(ArrayHeader) + sizeof(StorageType) * num_elements; | |
54 } | |
55 static Ref ToRef(StorageType* storage, size_t offset) { | |
56 return storage[offset]; | |
57 } | |
58 static ConstRef ToConstRef(const StorageType* storage, size_t offset) { | |
59 return storage[offset]; | |
60 } | |
61 }; | |
62 | |
63 template <typename P, bool is_union> | |
64 struct ObjectStorageType; | |
65 | |
66 template <typename P> | |
67 struct ObjectStorageType<P, true> { | |
68 typedef P Type; | |
69 }; | |
70 | |
71 template <typename P> | |
72 struct ObjectStorageType<P, false> { | |
73 typedef StructPointer<P> Type; | |
74 }; | |
75 | |
76 template <typename P> | |
77 struct ArrayDataTraits<P*> { | |
78 typedef typename ObjectStorageType<P, IsUnionDataType<P>::value>::Type | |
79 StorageType; | |
80 typedef P*& Ref; | |
81 typedef P* const& ConstRef; | |
82 | |
83 static const uint32_t kMaxNumElements = | |
84 (kMaxUint32 - sizeof(ArrayHeader)) / sizeof(StorageType); | |
85 | |
86 static uint32_t GetStorageSize(uint32_t num_elements) { | |
87 MOJO_DCHECK(num_elements <= kMaxNumElements); | |
88 return sizeof(ArrayHeader) + sizeof(StorageType) * num_elements; | |
89 } | |
90 static Ref ToRef(StorageType* storage, size_t offset) { | |
91 return storage[offset].ptr; | |
92 } | |
93 static ConstRef ToConstRef(const StorageType* storage, size_t offset) { | |
94 return storage[offset].ptr; | |
95 } | |
96 }; | |
97 | |
98 template <typename T> | |
99 struct ArrayDataTraits<Array_Data<T>*> { | |
100 typedef ArrayPointer<T> StorageType; | |
101 typedef Array_Data<T>*& Ref; | |
102 typedef Array_Data<T>* const& ConstRef; | |
103 | |
104 static const uint32_t kMaxNumElements = | |
105 (kMaxUint32 - sizeof(ArrayHeader)) / sizeof(StorageType); | |
106 | |
107 static uint32_t GetStorageSize(uint32_t num_elements) { | |
108 MOJO_DCHECK(num_elements <= kMaxNumElements); | |
109 return sizeof(ArrayHeader) + sizeof(StorageType) * num_elements; | |
110 } | |
111 static Ref ToRef(StorageType* storage, size_t offset) { | |
112 return storage[offset].ptr; | |
113 } | |
114 static ConstRef ToConstRef(const StorageType* storage, size_t offset) { | |
115 return storage[offset].ptr; | |
116 } | |
117 }; | |
118 | |
119 // Specialization of Arrays for bools, optimized for space. It has the | |
120 // following differences from a generalized Array: | |
121 // * Each element takes up a single bit of memory. | |
122 // * Accessing a non-const single element uses a helper class |BitRef|, which | |
123 // emulates a reference to a bool. | |
124 template <> | |
125 struct ArrayDataTraits<bool> { | |
126 // Helper class to emulate a reference to a bool, used for direct element | |
127 // access. | |
128 class BitRef { | |
129 public: | |
130 ~BitRef(); | |
131 BitRef& operator=(bool value); | |
132 BitRef& operator=(const BitRef& value); | |
133 operator bool() const; | |
134 | |
135 private: | |
136 friend struct ArrayDataTraits<bool>; | |
137 BitRef(uint8_t* storage, uint8_t mask); | |
138 BitRef(); | |
139 uint8_t* storage_; | |
140 uint8_t mask_; | |
141 }; | |
142 | |
143 // Because each element consumes only 1/8 byte. | |
144 static const uint32_t kMaxNumElements = kMaxUint32; | |
145 | |
146 typedef uint8_t StorageType; | |
147 typedef BitRef Ref; | |
148 typedef bool ConstRef; | |
149 | |
150 static uint32_t GetStorageSize(uint32_t num_elements) { | |
151 return sizeof(ArrayHeader) + ((num_elements + 7) / 8); | |
152 } | |
153 static BitRef ToRef(StorageType* storage, size_t offset) { | |
154 return BitRef(&storage[offset / 8], 1 << (offset % 8)); | |
155 } | |
156 static bool ToConstRef(const StorageType* storage, size_t offset) { | |
157 return (storage[offset / 8] & (1 << (offset % 8))) != 0; | |
158 } | |
159 }; | |
160 | |
161 // What follows is code to support the serialization of Array_Data<T>. There | |
162 // are two interesting cases: arrays of primitives/unions, arrays of non-union | |
163 // objects (structs, arrays and maps). | |
164 // Arrays of non-union objects are represented as arrays of pointers to objects. | |
165 // Arrays of primitives or unions are represented as arrays of the values | |
166 // themselves. | |
167 | |
168 template <typename T, bool is_handle, bool is_union> | |
169 struct ArraySerializationHelper; | |
170 | |
171 template <typename T> | |
172 struct ArraySerializationHelper<T, false, false> { | |
173 typedef typename ArrayDataTraits<T>::StorageType ElementType; | |
174 | |
175 static void EncodePointersAndHandles(const ArrayHeader* header, | |
176 ElementType* elements, | |
177 std::vector<Handle>* handles) {} | |
178 | |
179 static void DecodePointersAndHandles(const ArrayHeader* header, | |
180 ElementType* elements, | |
181 std::vector<Handle>* handles) {} | |
182 | |
183 static ValidationError ValidateElements( | |
184 const ArrayHeader* header, | |
185 const ElementType* elements, | |
186 BoundsChecker* bounds_checker, | |
187 const ArrayValidateParams* validate_params, | |
188 std::string* err) { | |
189 MOJO_DCHECK(!validate_params->element_is_nullable) | |
190 << "Primitive type should be non-nullable"; | |
191 MOJO_DCHECK(!validate_params->element_validate_params) | |
192 << "Primitive type should not have array validate params"; | |
193 return ValidationError::NONE; | |
194 } | |
195 }; | |
196 | |
197 template <> | |
198 struct ArraySerializationHelper<Handle, true, false> { | |
199 typedef ArrayDataTraits<Handle>::StorageType ElementType; | |
200 | |
201 static void EncodePointersAndHandles(const ArrayHeader* header, | |
202 ElementType* elements, | |
203 std::vector<Handle>* handles); | |
204 | |
205 static void DecodePointersAndHandles(const ArrayHeader* header, | |
206 ElementType* elements, | |
207 std::vector<Handle>* handles); | |
208 | |
209 static ValidationError ValidateElements( | |
210 const ArrayHeader* header, | |
211 const ElementType* elements, | |
212 BoundsChecker* bounds_checker, | |
213 const ArrayValidateParams* validate_params, | |
214 std::string* err) { | |
215 MOJO_DCHECK(!validate_params->element_validate_params) | |
216 << "Handle type should not have array validate params"; | |
217 | |
218 for (uint32_t i = 0; i < header->num_elements; ++i) { | |
219 if (!validate_params->element_is_nullable && | |
220 elements[i].value() == kEncodedInvalidHandleValue) { | |
221 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) | |
222 << "invalid handle in array expecting valid handles (array size=" | |
223 << header->num_elements << ", index = " << i << ")"; | |
224 return ValidationError::UNEXPECTED_INVALID_HANDLE; | |
225 } | |
226 if (!bounds_checker->ClaimHandle(elements[i])) { | |
227 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) << ""; | |
228 return ValidationError::ILLEGAL_HANDLE; | |
229 } | |
230 } | |
231 return ValidationError::NONE; | |
232 } | |
233 }; | |
234 | |
235 template <typename H> | |
236 struct ArraySerializationHelper<H, true, false> { | |
237 typedef typename ArrayDataTraits<H>::StorageType ElementType; | |
238 | |
239 static void EncodePointersAndHandles(const ArrayHeader* header, | |
240 ElementType* elements, | |
241 std::vector<Handle>* handles) { | |
242 ArraySerializationHelper<Handle, true, false>::EncodePointersAndHandles( | |
243 header, elements, handles); | |
244 } | |
245 | |
246 static void DecodePointersAndHandles(const ArrayHeader* header, | |
247 ElementType* elements, | |
248 std::vector<Handle>* handles) { | |
249 ArraySerializationHelper<Handle, true, false>::DecodePointersAndHandles( | |
250 header, elements, handles); | |
251 } | |
252 | |
253 static ValidationError ValidateElements( | |
254 const ArrayHeader* header, | |
255 const ElementType* elements, | |
256 BoundsChecker* bounds_checker, | |
257 const ArrayValidateParams* validate_params, | |
258 std::string* err) { | |
259 return ArraySerializationHelper<Handle, true, false>::ValidateElements( | |
260 header, elements, bounds_checker, validate_params, err); | |
261 } | |
262 }; | |
263 | |
264 template <typename P> | |
265 struct ArraySerializationHelper<P*, false, false> { | |
266 typedef typename ArrayDataTraits<P*>::StorageType ElementType; | |
267 | |
268 static void EncodePointersAndHandles(const ArrayHeader* header, | |
269 ElementType* elements, | |
270 std::vector<Handle>* handles) { | |
271 for (uint32_t i = 0; i < header->num_elements; ++i) | |
272 Encode(&elements[i], handles); | |
273 } | |
274 | |
275 static void DecodePointersAndHandles(const ArrayHeader* header, | |
276 ElementType* elements, | |
277 std::vector<Handle>* handles) { | |
278 for (uint32_t i = 0; i < header->num_elements; ++i) | |
279 Decode(&elements[i], handles); | |
280 } | |
281 | |
282 static ValidationError ValidateElements( | |
283 const ArrayHeader* header, | |
284 const ElementType* elements, | |
285 BoundsChecker* bounds_checker, | |
286 const ArrayValidateParams* validate_params, | |
287 std::string* err) { | |
288 for (uint32_t i = 0; i < header->num_elements; ++i) { | |
289 if (!validate_params->element_is_nullable && !elements[i].offset) { | |
290 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) | |
291 << "null in array expecting valid pointers (size=" | |
292 << header->num_elements << ", index = " << i << ")"; | |
293 return ValidationError::UNEXPECTED_NULL_POINTER; | |
294 } | |
295 | |
296 if (!ValidateEncodedPointer(&elements[i].offset)) { | |
297 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) << ""; | |
298 return ValidationError::ILLEGAL_POINTER; | |
299 } | |
300 | |
301 auto retval = ValidateCaller<P>::Run( | |
302 DecodePointerRaw(&elements[i].offset), bounds_checker, | |
303 validate_params->element_validate_params, err); | |
304 if (retval != ValidationError::NONE) | |
305 return retval; | |
306 } | |
307 return ValidationError::NONE; | |
308 } | |
309 | |
310 private: | |
311 template <typename T> | |
312 struct ValidateCaller { | |
313 static ValidationError Run(const void* data, | |
314 BoundsChecker* bounds_checker, | |
315 const ArrayValidateParams* validate_params, | |
316 std::string* err) { | |
317 MOJO_DCHECK(!validate_params) | |
318 << "Struct type should not have array validate params"; | |
319 | |
320 return T::Validate(data, bounds_checker, err); | |
321 } | |
322 }; | |
323 | |
324 template <typename Key, typename Value> | |
325 struct ValidateCaller<Map_Data<Key, Value>> { | |
326 static ValidationError Run(const void* data, | |
327 BoundsChecker* bounds_checker, | |
328 const ArrayValidateParams* validate_params, | |
329 std::string* err) { | |
330 return Map_Data<Key, Value>::Validate(data, bounds_checker, | |
331 validate_params, err); | |
332 } | |
333 }; | |
334 | |
335 template <typename T> | |
336 struct ValidateCaller<Array_Data<T>> { | |
337 static ValidationError Run(const void* data, | |
338 BoundsChecker* bounds_checker, | |
339 const ArrayValidateParams* validate_params, | |
340 std::string* err) { | |
341 return Array_Data<T>::Validate(data, bounds_checker, validate_params, | |
342 err); | |
343 } | |
344 }; | |
345 }; | |
346 | |
347 // Array Serialization Helper for unions. | |
348 template <typename P> | |
349 struct ArraySerializationHelper<P, false, true> { | |
350 typedef P ElementType; | |
351 | |
352 static void EncodePointersAndHandles(const ArrayHeader* header, | |
353 ElementType* elements, | |
354 std::vector<Handle>* handles) { | |
355 for (uint32_t i = 0; i < header->num_elements; ++i) | |
356 elements[i].EncodePointersAndHandles(handles); | |
357 } | |
358 | |
359 static void DecodePointersAndHandles(const ArrayHeader* header, | |
360 ElementType* elements, | |
361 std::vector<Handle>* handles) { | |
362 for (uint32_t i = 0; i < header->num_elements; ++i) | |
363 elements[i].DecodePointersAndHandles(handles); | |
364 } | |
365 | |
366 static ValidationError ValidateElements( | |
367 const ArrayHeader* header, | |
368 const ElementType* elements, | |
369 BoundsChecker* bounds_checker, | |
370 const ArrayValidateParams* validate_params, | |
371 std::string* err) { | |
372 MOJO_DCHECK(!validate_params->element_validate_params) | |
373 << "Union type should not have array validate params"; | |
374 for (uint32_t i = 0; i < header->num_elements; ++i) { | |
375 if (!validate_params->element_is_nullable && elements[i].is_null()) { | |
376 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) | |
377 << "null union in array expecting non-null unions (size=" | |
378 << header->num_elements << ", index = " << i << ")"; | |
379 return ValidationError::UNEXPECTED_NULL_UNION; | |
380 } | |
381 | |
382 auto retval = ElementType::Validate( | |
383 static_cast<const void*>(&elements[i]), bounds_checker, true, err); | |
384 if (retval != ValidationError::NONE) | |
385 return retval; | |
386 } | |
387 return ValidationError::NONE; | |
388 } | |
389 }; | |
390 | |
391 template <typename T> | |
392 class Array_Data { | |
393 public: | |
394 typedef ArrayDataTraits<T> Traits; | |
395 typedef typename Traits::StorageType StorageType; | |
396 typedef typename Traits::Ref Ref; | |
397 typedef typename Traits::ConstRef ConstRef; | |
398 typedef ArraySerializationHelper< | |
399 T, | |
400 IsHandle<T>::value, | |
401 IsUnionDataType<typename std::remove_pointer<T>::type>::value> Helper; | |
402 | |
403 // Returns null if |num_elements| or the corresponding storage size cannot be | |
404 // stored in uint32_t. | |
405 static Array_Data<T>* New(size_t num_elements, Buffer* buf) { | |
406 if (num_elements > Traits::kMaxNumElements) | |
407 return nullptr; | |
408 | |
409 uint32_t num_bytes = | |
410 Traits::GetStorageSize(static_cast<uint32_t>(num_elements)); | |
411 return new (buf->Allocate(num_bytes)) | |
412 Array_Data<T>(num_bytes, static_cast<uint32_t>(num_elements)); | |
413 } | |
414 | |
415 static ValidationError Validate(const void* data, | |
416 BoundsChecker* bounds_checker, | |
417 const ArrayValidateParams* validate_params, | |
418 std::string* err) { | |
419 if (!data) | |
420 return ValidationError::NONE; | |
421 if (!IsAligned(data)) { | |
422 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) << ""; | |
423 return ValidationError::MISALIGNED_OBJECT; | |
424 } | |
425 if (!bounds_checker->IsValidRange(data, sizeof(ArrayHeader))) { | |
426 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) << ""; | |
427 return ValidationError::ILLEGAL_MEMORY_RANGE; | |
428 } | |
429 | |
430 const ArrayHeader* header = static_cast<const ArrayHeader*>(data); | |
431 if (header->num_elements > Traits::kMaxNumElements || | |
432 header->num_bytes < Traits::GetStorageSize(header->num_elements)) { | |
433 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) << ""; | |
434 return ValidationError::UNEXPECTED_ARRAY_HEADER; | |
435 } | |
436 | |
437 if (validate_params->expected_num_elements != 0 && | |
438 header->num_elements != validate_params->expected_num_elements) { | |
439 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) | |
440 << "fixed-size array has wrong number of elements (size=" | |
441 << header->num_elements | |
442 << ", expected size=" << validate_params->expected_num_elements | |
443 << ")"; | |
444 return ValidationError::UNEXPECTED_ARRAY_HEADER; | |
445 } | |
446 | |
447 if (!bounds_checker->ClaimMemory(data, header->num_bytes)) { | |
448 MOJO_INTERNAL_DEBUG_SET_ERROR_MSG(err) << ""; | |
449 return ValidationError::ILLEGAL_MEMORY_RANGE; | |
450 } | |
451 | |
452 const Array_Data<T>* object = static_cast<const Array_Data<T>*>(data); | |
453 return Helper::ValidateElements(&object->header_, object->storage(), | |
454 bounds_checker, validate_params, err); | |
455 } | |
456 | |
457 size_t size() const { return header_.num_elements; } | |
458 | |
459 Ref at(size_t offset) { | |
460 MOJO_DCHECK(offset < static_cast<size_t>(header_.num_elements)); | |
461 return Traits::ToRef(storage(), offset); | |
462 } | |
463 | |
464 ConstRef at(size_t offset) const { | |
465 MOJO_DCHECK(offset < static_cast<size_t>(header_.num_elements)); | |
466 return Traits::ToConstRef(storage(), offset); | |
467 } | |
468 | |
469 StorageType* storage() { | |
470 return reinterpret_cast<StorageType*>(reinterpret_cast<char*>(this) + | |
471 sizeof(*this)); | |
472 } | |
473 | |
474 const StorageType* storage() const { | |
475 return reinterpret_cast<const StorageType*>( | |
476 reinterpret_cast<const char*>(this) + sizeof(*this)); | |
477 } | |
478 | |
479 void EncodePointersAndHandles(std::vector<Handle>* handles) { | |
480 Helper::EncodePointersAndHandles(&header_, storage(), handles); | |
481 } | |
482 | |
483 void DecodePointersAndHandles(std::vector<Handle>* handles) { | |
484 Helper::DecodePointersAndHandles(&header_, storage(), handles); | |
485 } | |
486 | |
487 private: | |
488 Array_Data(uint32_t num_bytes, uint32_t num_elements) { | |
489 header_.num_bytes = num_bytes; | |
490 header_.num_elements = num_elements; | |
491 } | |
492 ~Array_Data() = delete; | |
493 | |
494 internal::ArrayHeader header_; | |
495 | |
496 // Elements of type internal::ArrayDataTraits<T>::StorageType follow. | |
497 }; | |
498 static_assert(sizeof(Array_Data<char>) == 8, "Bad sizeof(Array_Data)"); | |
499 | |
500 // UTF-8 encoded | |
501 typedef Array_Data<char> String_Data; | |
502 | |
503 template <typename T, bool kIsMoveOnlyType> | |
504 struct ArrayTraits {}; | |
505 | |
506 template <typename T> | |
507 struct ArrayTraits<T, false> { | |
508 typedef typename std::vector<T>::const_reference ForwardType; | |
509 static inline void PushBack(std::vector<T>* vec, ForwardType value) { | |
510 vec->push_back(value); | |
511 } | |
512 static inline void Clone(const std::vector<T>& src_vec, | |
513 std::vector<T>* dest_vec) { | |
514 dest_vec->assign(src_vec.begin(), src_vec.end()); | |
515 } | |
516 }; | |
517 | |
518 template <typename T> | |
519 struct ArrayTraits<T, true> { | |
520 typedef T ForwardType; | |
521 static inline void PushBack(std::vector<T>* vec, T& value) { | |
522 vec->push_back(value.Pass()); | |
523 } | |
524 static inline void Clone(const std::vector<T>& src_vec, | |
525 std::vector<T>* dest_vec) { | |
526 dest_vec->resize(src_vec.size()); | |
527 for (size_t i = 0; i < src_vec.size(); ++i) | |
528 dest_vec->at(i) = src_vec.at(i).Clone(); | |
529 } | |
530 }; | |
531 | |
532 template <> | |
533 struct WrapperTraits<String, false> { | |
534 typedef String_Data* DataType; | |
535 }; | |
536 | |
537 } // namespace internal | |
538 } // namespace mojo | |
539 | |
540 #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_ | |
OLD | NEW |