14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
24e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
34e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// found in the LICENSE file.
44e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "mojo/public/cpp/bindings/lib/bindings_serialization.h"
64e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
7e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "mojo/public/cpp/bindings/lib/bounds_checker.h"
946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "mojo/public/cpp/bindings/lib/validation_errors.h"
105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "mojo/public/cpp/environment/logging.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace mojo {
134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace internal {
144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
15010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)namespace {
16010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
1746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)const size_t kAlignment = 8;
1846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
19010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)template<typename T>
20010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)T AlignImpl(T t) {
21010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return t + (kAlignment - (t % kAlignment)) % kAlignment;
22010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
23010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
24010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}  // namespace
25010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
26010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)size_t Align(size_t size) {
27010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return AlignImpl(size);
28010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
29010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
30010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)char* AlignPointer(char* ptr) {
31010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return reinterpret_cast<char*>(AlignImpl(reinterpret_cast<uintptr_t>(ptr)));
324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)bool IsAligned(const void* ptr) {
3546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return !(reinterpret_cast<uintptr_t>(ptr) % kAlignment);
3646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
3746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void EncodePointer(const void* ptr, uint64_t* offset) {
394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!ptr) {
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    *offset = 0;
414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const char* p_obj = reinterpret_cast<const char*>(ptr);
454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const char* p_slot = reinterpret_cast<const char*>(offset);
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  MOJO_DCHECK(p_obj > p_slot);
474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  *offset = static_cast<uint64_t>(p_obj - p_slot);
494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const void* DecodePointerRaw(const uint64_t* offset) {
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!*offset)
534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return NULL;
544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return reinterpret_cast<const char*>(offset) + *offset;
554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)bool ValidateEncodedPointer(const uint64_t* offset) {
5846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Cast to uintptr_t so overflow behavior is well defined.
5946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return reinterpret_cast<uintptr_t>(offset) + *offset >=
6046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      reinterpret_cast<uintptr_t>(offset);
614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void EncodeHandle(Handle* handle, std::vector<Handle>* handles) {
64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (handle->is_valid()) {
65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    handles->push_back(*handle);
66a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    handle->set_value(static_cast<MojoHandle>(handles->size() - 1));
67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  } else {
6846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    handle->set_value(kEncodedInvalidHandleValue);
69a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
7246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void DecodeHandle(Handle* handle, std::vector<Handle>* handles) {
7346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (handle->value() == kEncodedInvalidHandleValue) {
74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    *handle = Handle();
7546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
76a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  MOJO_DCHECK(handle->value() < handles->size());
78a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Just leave holes in the vector so we don't screw up other indices.
79a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  *handle = FetchAndReset(&handles->at(handle->value()));
8046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
8146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
8246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)bool ValidateStructHeader(const void* data,
8346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                          uint32_t min_num_bytes,
8446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                          uint32_t min_num_fields,
8546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                          BoundsChecker* bounds_checker) {
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  MOJO_DCHECK(min_num_bytes >= sizeof(StructHeader));
87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
8846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!IsAligned(data)) {
8946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    ReportValidationError(VALIDATION_ERROR_MISALIGNED_OBJECT);
9046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return false;
9146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
9246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!bounds_checker->IsValidRange(data, sizeof(StructHeader))) {
9346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
9446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return false;
9546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
9646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
9746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const StructHeader* header = static_cast<const StructHeader*>(data);
9846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
9946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // TODO(yzshen): Currently our binding code cannot handle structs of smaller
10046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // size or with fewer fields than the version that it sees. That needs to be
10146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // changed in order to provide backward compatibility.
10246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (header->num_bytes < min_num_bytes ||
10346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      header->num_fields < min_num_fields) {
10446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    ReportValidationError(VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER);
10546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return false;
10646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
10746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
10846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!bounds_checker->ClaimMemory(data, header->num_bytes)) {
10946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    ReportValidationError(VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE);
11046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return false;
11146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
11246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return true;
1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace internal
1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace mojo
118