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