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 #include "mojo/public/cpp/bindings/lib/bindings_serialization.h"
      6 
      7 #include "mojo/public/cpp/bindings/lib/bindings_internal.h"
      8 #include "mojo/public/cpp/bindings/lib/bounds_checker.h"
      9 #include "mojo/public/cpp/bindings/lib/validation_errors.h"
     10 #include "mojo/public/cpp/environment/logging.h"
     11 
     12 namespace mojo {
     13 namespace internal {
     14 
     15 namespace {
     16 
     17 const size_t kAlignment = 8;
     18 
     19 template<typename T>
     20 T AlignImpl(T t) {
     21   return t + (kAlignment - (t % kAlignment)) % kAlignment;
     22 }
     23 
     24 }  // namespace
     25 
     26 size_t Align(size_t size) {
     27   return AlignImpl(size);
     28 }
     29 
     30 char* AlignPointer(char* ptr) {
     31   return reinterpret_cast<char*>(AlignImpl(reinterpret_cast<uintptr_t>(ptr)));
     32 }
     33 
     34 bool IsAligned(const void* ptr) {
     35   return !(reinterpret_cast<uintptr_t>(ptr) % kAlignment);
     36 }
     37 
     38 void EncodePointer(const void* ptr, uint64_t* offset) {
     39   if (!ptr) {
     40     *offset = 0;
     41     return;
     42   }
     43 
     44   const char* p_obj = reinterpret_cast<const char*>(ptr);
     45   const char* p_slot = reinterpret_cast<const char*>(offset);
     46   MOJO_DCHECK(p_obj > p_slot);
     47 
     48   *offset = static_cast<uint64_t>(p_obj - p_slot);
     49 }
     50 
     51 const void* DecodePointerRaw(const uint64_t* offset) {
     52   if (!*offset)
     53     return NULL;
     54   return reinterpret_cast<const char*>(offset) + *offset;
     55 }
     56 
     57 bool ValidateEncodedPointer(const uint64_t* offset) {
     58   // Cast to uintptr_t so overflow behavior is well defined.
     59   return reinterpret_cast<uintptr_t>(offset) + *offset >=
     60       reinterpret_cast<uintptr_t>(offset);
     61 }
     62 
     63 void EncodeHandle(Handle* handle, std::vector<Handle>* handles) {
     64   if (handle->is_valid()) {
     65     handles->push_back(*handle);
     66     handle->set_value(static_cast<MojoHandle>(handles->size() - 1));
     67   } else {
     68     handle->set_value(kEncodedInvalidHandleValue);
     69   }
     70 }
     71 
     72 void DecodeHandle(Handle* handle, std::vector<Handle>* handles) {
     73   if (handle->value() == kEncodedInvalidHandleValue) {
     74     *handle = Handle();
     75     return;
     76   }
     77   MOJO_DCHECK(handle->value() < handles->size());
     78   // Just leave holes in the vector so we don't screw up other indices.
     79   *handle = FetchAndReset(&handles->at(handle->value()));
     80 }
     81 
     82 bool ValidateStructHeader(const void* data,
     83                           uint32_t min_num_bytes,
     84                           uint32_t min_num_fields,
     85                           BoundsChecker* bounds_checker) {
     86   MOJO_DCHECK(min_num_bytes >= sizeof(StructHeader));
     87 
     88   if (!IsAligned(data)) {
     89     ReportValidationError(VALIDATION_ERROR_MISALIGNED_OBJECT);
     90     return false;
     91   }
     92   if (!bounds_checker->IsValidRange(data, sizeof(StructHeader))) {
     93     ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
     94     return false;
     95   }
     96 
     97   const StructHeader* header = static_cast<const StructHeader*>(data);
     98 
     99   // TODO(yzshen): Currently our binding code cannot handle structs of smaller
    100   // size or with fewer fields than the version that it sees. That needs to be
    101   // changed in order to provide backward compatibility.
    102   if (header->num_bytes < min_num_bytes ||
    103       header->num_fields < min_num_fields) {
    104     ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
    105     return false;
    106   }
    107 
    108   if (!bounds_checker->ClaimMemory(data, header->num_bytes)) {
    109     ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
    110     return false;
    111   }
    112 
    113   return true;
    114 }
    115 
    116 }  // namespace internal
    117 }  // namespace mojo
    118