Home | History | Annotate | Download | only in lib
      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 <stddef.h>
      9 #include <stdint.h>
     10 
     11 #include <limits>
     12 #include <new>
     13 
     14 #include "base/logging.h"
     15 #include "mojo/public/c/system/macros.h"
     16 #include "mojo/public/cpp/bindings/lib/bindings_internal.h"
     17 #include "mojo/public/cpp/bindings/lib/buffer.h"
     18 #include "mojo/public/cpp/bindings/lib/serialization_util.h"
     19 #include "mojo/public/cpp/bindings/lib/template_util.h"
     20 #include "mojo/public/cpp/bindings/lib/validate_params.h"
     21 #include "mojo/public/cpp/bindings/lib/validation_context.h"
     22 #include "mojo/public/cpp/bindings/lib/validation_errors.h"
     23 #include "mojo/public/cpp/bindings/lib/validation_util.h"
     24 
     25 namespace mojo {
     26 namespace internal {
     27 
     28 template <typename K, typename V>
     29 class Map_Data;
     30 
     31 std::string MakeMessageWithArrayIndex(const char* message,
     32                                       size_t size,
     33                                       size_t index);
     34 
     35 std::string MakeMessageWithExpectedArraySize(const char* message,
     36                                              size_t size,
     37                                              size_t expected_size);
     38 
     39 template <typename T>
     40 struct ArrayDataTraits {
     41   using StorageType = T;
     42   using Ref = T&;
     43   using ConstRef = const T&;
     44 
     45   static const uint32_t kMaxNumElements =
     46       (std::numeric_limits<uint32_t>::max() - sizeof(ArrayHeader)) /
     47       sizeof(StorageType);
     48 
     49   static uint32_t GetStorageSize(uint32_t num_elements) {
     50     DCHECK(num_elements <= kMaxNumElements);
     51     return sizeof(ArrayHeader) + sizeof(StorageType) * num_elements;
     52   }
     53   static Ref ToRef(StorageType* storage, size_t offset) {
     54     return storage[offset];
     55   }
     56   static ConstRef ToConstRef(const StorageType* storage, size_t offset) {
     57     return storage[offset];
     58   }
     59 };
     60 
     61 // Specialization of Arrays for bools, optimized for space. It has the
     62 // following differences from a generalized Array:
     63 // * Each element takes up a single bit of memory.
     64 // * Accessing a non-const single element uses a helper class |BitRef|, which
     65 // emulates a reference to a bool.
     66 template <>
     67 struct ArrayDataTraits<bool> {
     68   // Helper class to emulate a reference to a bool, used for direct element
     69   // access.
     70   class BitRef {
     71    public:
     72     ~BitRef();
     73     BitRef& operator=(bool value);
     74     BitRef& operator=(const BitRef& value);
     75     operator bool() const;
     76 
     77    private:
     78     friend struct ArrayDataTraits<bool>;
     79     BitRef(uint8_t* storage, uint8_t mask);
     80     BitRef();
     81     uint8_t* storage_;
     82     uint8_t mask_;
     83   };
     84 
     85   // Because each element consumes only 1/8 byte.
     86   static const uint32_t kMaxNumElements = std::numeric_limits<uint32_t>::max();
     87 
     88   using StorageType = uint8_t;
     89   using Ref = BitRef;
     90   using ConstRef = bool;
     91 
     92   static uint32_t GetStorageSize(uint32_t num_elements) {
     93     return sizeof(ArrayHeader) + ((num_elements + 7) / 8);
     94   }
     95   static BitRef ToRef(StorageType* storage, size_t offset) {
     96     return BitRef(&storage[offset / 8], 1 << (offset % 8));
     97   }
     98   static bool ToConstRef(const StorageType* storage, size_t offset) {
     99     return (storage[offset / 8] & (1 << (offset % 8))) != 0;
    100   }
    101 };
    102 
    103 // What follows is code to support the serialization/validation of
    104 // Array_Data<T>. There are four interesting cases: arrays of primitives,
    105 // arrays of handles/interfaces, arrays of objects and arrays of unions.
    106 // Arrays of objects are represented as arrays of pointers to objects. Arrays
    107 // of unions are inlined so they are not pointers, but comparing with primitives
    108 // they require more work for serialization/validation.
    109 //
    110 // TODO(yzshen): Validation code should be organzied in a way similar to
    111 // Serializer<>, or merged into it. It should be templatized with the mojo
    112 // wrapper type instead of the data type, that way we can use MojomTypeTraits
    113 // to determine the categories.
    114 
    115 template <typename T, bool is_union, bool is_handle_or_interface>
    116 struct ArraySerializationHelper;
    117 
    118 template <typename T>
    119 struct ArraySerializationHelper<T, false, false> {
    120   using ElementType = typename ArrayDataTraits<T>::StorageType;
    121 
    122   static bool ValidateElements(const ArrayHeader* header,
    123                                const ElementType* elements,
    124                                ValidationContext* validation_context,
    125                                const ContainerValidateParams* validate_params) {
    126     DCHECK(!validate_params->element_is_nullable)
    127         << "Primitive type should be non-nullable";
    128     DCHECK(!validate_params->element_validate_params)
    129         << "Primitive type should not have array validate params";
    130 
    131     if (!validate_params->validate_enum_func)
    132       return true;
    133 
    134     // Enum validation.
    135     for (uint32_t i = 0; i < header->num_elements; ++i) {
    136       if (!validate_params->validate_enum_func(elements[i], validation_context))
    137         return false;
    138     }
    139     return true;
    140   }
    141 };
    142 
    143 template <typename T>
    144 struct ArraySerializationHelper<T, false, true> {
    145   using ElementType = typename ArrayDataTraits<T>::StorageType;
    146 
    147   static bool ValidateElements(const ArrayHeader* header,
    148                                const ElementType* elements,
    149                                ValidationContext* validation_context,
    150                                const ContainerValidateParams* validate_params) {
    151     DCHECK(!validate_params->element_validate_params)
    152         << "Handle or interface type should not have array validate params";
    153 
    154     for (uint32_t i = 0; i < header->num_elements; ++i) {
    155       if (!validate_params->element_is_nullable &&
    156           !IsHandleOrInterfaceValid(elements[i])) {
    157         static const ValidationError kError =
    158             std::is_same<T, Interface_Data>::value ||
    159                     std::is_same<T, Handle_Data>::value
    160                 ? VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE
    161                 : VALIDATION_ERROR_UNEXPECTED_INVALID_INTERFACE_ID;
    162         ReportValidationError(
    163             validation_context, kError,
    164             MakeMessageWithArrayIndex(
    165                 "invalid handle or interface ID in array expecting valid "
    166                 "handles or interface IDs",
    167                 header->num_elements, i)
    168                 .c_str());
    169         return false;
    170       }
    171       if (!ValidateHandleOrInterface(elements[i], validation_context))
    172         return false;
    173     }
    174     return true;
    175   }
    176 };
    177 
    178 template <typename T>
    179 struct ArraySerializationHelper<Pointer<T>, false, false> {
    180   using ElementType = typename ArrayDataTraits<Pointer<T>>::StorageType;
    181 
    182   static bool ValidateElements(const ArrayHeader* header,
    183                                const ElementType* elements,
    184                                ValidationContext* validation_context,
    185                                const ContainerValidateParams* validate_params) {
    186     for (uint32_t i = 0; i < header->num_elements; ++i) {
    187       if (!validate_params->element_is_nullable && !elements[i].offset) {
    188         ReportValidationError(
    189             validation_context,
    190             VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
    191             MakeMessageWithArrayIndex("null in array expecting valid pointers",
    192                                       header->num_elements,
    193                                       i).c_str());
    194         return false;
    195       }
    196       if (!ValidateCaller<T>::Run(elements[i], validation_context,
    197                                   validate_params->element_validate_params)) {
    198         return false;
    199       }
    200     }
    201     return true;
    202   }
    203 
    204  private:
    205   template <typename U,
    206             bool is_array_or_map = IsSpecializationOf<Array_Data, U>::value ||
    207                                    IsSpecializationOf<Map_Data, U>::value>
    208   struct ValidateCaller {
    209     static bool Run(const Pointer<U>& data,
    210                     ValidationContext* validation_context,
    211                     const ContainerValidateParams* validate_params) {
    212       DCHECK(!validate_params)
    213           << "Struct type should not have array validate params";
    214 
    215       return ValidateStruct(data, validation_context);
    216     }
    217   };
    218 
    219   template <typename U>
    220   struct ValidateCaller<U, true> {
    221     static bool Run(const Pointer<U>& data,
    222                     ValidationContext* validation_context,
    223                     const ContainerValidateParams* validate_params) {
    224       return ValidateContainer(data, validation_context, validate_params);
    225     }
    226   };
    227 };
    228 
    229 template <typename U>
    230 struct ArraySerializationHelper<U, true, false> {
    231   using ElementType = typename ArrayDataTraits<U>::StorageType;
    232 
    233   static bool ValidateElements(const ArrayHeader* header,
    234                                const ElementType* elements,
    235                                ValidationContext* validation_context,
    236                                const ContainerValidateParams* validate_params) {
    237     for (uint32_t i = 0; i < header->num_elements; ++i) {
    238       if (!validate_params->element_is_nullable && elements[i].is_null()) {
    239         ReportValidationError(
    240             validation_context,
    241             VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
    242             MakeMessageWithArrayIndex("null in array expecting valid unions",
    243                                       header->num_elements, i)
    244                 .c_str());
    245         return false;
    246       }
    247       if (!ValidateInlinedUnion(elements[i], validation_context))
    248         return false;
    249     }
    250     return true;
    251   }
    252 };
    253 
    254 template <typename T>
    255 class Array_Data {
    256  public:
    257   using Traits = ArrayDataTraits<T>;
    258   using StorageType = typename Traits::StorageType;
    259   using Ref = typename Traits::Ref;
    260   using ConstRef = typename Traits::ConstRef;
    261   using Helper = ArraySerializationHelper<
    262       T,
    263       IsUnionDataType<T>::value,
    264       std::is_same<T, AssociatedInterface_Data>::value ||
    265           std::is_same<T, AssociatedInterfaceRequest_Data>::value ||
    266           std::is_same<T, Interface_Data>::value ||
    267           std::is_same<T, Handle_Data>::value>;
    268   using Element = T;
    269 
    270   // Returns null if |num_elements| or the corresponding storage size cannot be
    271   // stored in uint32_t.
    272   static Array_Data<T>* New(size_t num_elements, Buffer* buf) {
    273     if (num_elements > Traits::kMaxNumElements)
    274       return nullptr;
    275 
    276     uint32_t num_bytes =
    277         Traits::GetStorageSize(static_cast<uint32_t>(num_elements));
    278     return new (buf->Allocate(num_bytes))
    279         Array_Data<T>(num_bytes, static_cast<uint32_t>(num_elements));
    280   }
    281 
    282   static bool Validate(const void* data,
    283                        ValidationContext* validation_context,
    284                        const ContainerValidateParams* validate_params) {
    285     if (!data)
    286       return true;
    287     if (!IsAligned(data)) {
    288       ReportValidationError(validation_context,
    289                             VALIDATION_ERROR_MISALIGNED_OBJECT);
    290       return false;
    291     }
    292     if (!validation_context->IsValidRange(data, sizeof(ArrayHeader))) {
    293       ReportValidationError(validation_context,
    294                             VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
    295       return false;
    296     }
    297     const ArrayHeader* header = static_cast<const ArrayHeader*>(data);
    298     if (header->num_elements > Traits::kMaxNumElements ||
    299         header->num_bytes < Traits::GetStorageSize(header->num_elements)) {
    300       ReportValidationError(validation_context,
    301                             VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER);
    302       return false;
    303     }
    304     if (validate_params->expected_num_elements != 0 &&
    305         header->num_elements != validate_params->expected_num_elements) {
    306       ReportValidationError(
    307           validation_context,
    308           VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER,
    309           MakeMessageWithExpectedArraySize(
    310               "fixed-size array has wrong number of elements",
    311               header->num_elements,
    312               validate_params->expected_num_elements).c_str());
    313       return false;
    314     }
    315     if (!validation_context->ClaimMemory(data, header->num_bytes)) {
    316       ReportValidationError(validation_context,
    317                             VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
    318       return false;
    319     }
    320 
    321     const Array_Data<T>* object = static_cast<const Array_Data<T>*>(data);
    322     return Helper::ValidateElements(&object->header_, object->storage(),
    323                                     validation_context, validate_params);
    324   }
    325 
    326   size_t size() const { return header_.num_elements; }
    327 
    328   Ref at(size_t offset) {
    329     DCHECK(offset < static_cast<size_t>(header_.num_elements));
    330     return Traits::ToRef(storage(), offset);
    331   }
    332 
    333   ConstRef at(size_t offset) const {
    334     DCHECK(offset < static_cast<size_t>(header_.num_elements));
    335     return Traits::ToConstRef(storage(), offset);
    336   }
    337 
    338   StorageType* storage() {
    339     return reinterpret_cast<StorageType*>(reinterpret_cast<char*>(this) +
    340                                           sizeof(*this));
    341   }
    342 
    343   const StorageType* storage() const {
    344     return reinterpret_cast<const StorageType*>(
    345         reinterpret_cast<const char*>(this) + sizeof(*this));
    346   }
    347 
    348  private:
    349   Array_Data(uint32_t num_bytes, uint32_t num_elements) {
    350     header_.num_bytes = num_bytes;
    351     header_.num_elements = num_elements;
    352   }
    353   ~Array_Data() = delete;
    354 
    355   internal::ArrayHeader header_;
    356 
    357   // Elements of type internal::ArrayDataTraits<T>::StorageType follow.
    358 };
    359 static_assert(sizeof(Array_Data<char>) == 8, "Bad sizeof(Array_Data)");
    360 
    361 // UTF-8 encoded
    362 using String_Data = Array_Data<char>;
    363 
    364 }  // namespace internal
    365 }  // namespace mojo
    366 
    367 #endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_INTERNAL_H_
    368