OLD | NEW |
| (Empty) |
1 // Copyright 2016 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/c/bindings/lib/type_descriptor.h" | |
6 | |
7 #include <assert.h> | |
8 #include <stddef.h> | |
9 | |
10 #include "mojo/public/c/bindings/array.h" | |
11 #include "mojo/public/c/bindings/interface.h" | |
12 #include "mojo/public/c/bindings/lib/util.h" | |
13 #include "mojo/public/c/bindings/map.h" | |
14 #include "mojo/public/c/bindings/struct.h" | |
15 #include "mojo/public/c/bindings/union.h" | |
16 | |
17 const struct MojomTypeDescriptorArray g_mojom_string_type_description = { | |
18 .elem_type = MOJOM_TYPE_DESCRIPTOR_TYPE_POD, | |
19 .elem_descriptor = NULL, | |
20 .num_elements = 0, | |
21 .elem_num_bits = 8, | |
22 .nullable = false, | |
23 }; | |
24 | |
25 // The encoding of a MojoHandle is an index into an array of Handles. A | |
26 // null/invalid handle is encoded as index (which is unsigned) "-1", which | |
27 // equates to the highest possible index. | |
28 static const MojoHandle kEncodedHandleInvalid = (MojoHandle)-1; | |
29 | |
30 bool MojomType_IsPointer(enum MojomTypeDescriptorType type) { | |
31 return type == MOJOM_TYPE_DESCRIPTOR_TYPE_STRUCT_PTR || | |
32 type == MOJOM_TYPE_DESCRIPTOR_TYPE_MAP_PTR || | |
33 type == MOJOM_TYPE_DESCRIPTOR_TYPE_ARRAY_PTR || | |
34 type == MOJOM_TYPE_DESCRIPTOR_TYPE_UNION_PTR; | |
35 } | |
36 | |
37 size_t MojomType_DispatchComputeSerializedSize( | |
38 enum MojomTypeDescriptorType type, | |
39 const void* type_desc, | |
40 bool nullable, | |
41 const void* data) { | |
42 const void* data_ptr = data; | |
43 size_t size = 0; | |
44 switch (type) { | |
45 case MOJOM_TYPE_DESCRIPTOR_TYPE_MAP_PTR: | |
46 case MOJOM_TYPE_DESCRIPTOR_TYPE_STRUCT_PTR: { | |
47 data_ptr = ((const union MojomPointer*)data_ptr)->ptr; | |
48 if (!nullable || data_ptr != NULL) | |
49 return MojomStruct_ComputeSerializedSize( | |
50 (const struct MojomTypeDescriptorStruct*)type_desc, | |
51 (const struct MojomStructHeader*)data_ptr); | |
52 break; | |
53 } | |
54 case MOJOM_TYPE_DESCRIPTOR_TYPE_ARRAY_PTR: | |
55 data_ptr = ((const union MojomPointer*)data_ptr)->ptr; | |
56 if (!nullable || data_ptr != NULL) | |
57 return MojomArray_ComputeSerializedSize(type_desc, data_ptr); | |
58 break; | |
59 case MOJOM_TYPE_DESCRIPTOR_TYPE_UNION_PTR: | |
60 data_ptr = ((const union MojomPointer*)data_ptr)->ptr; | |
61 if (data_ptr != NULL) | |
62 size = sizeof(struct MojomUnionLayout); | |
63 // Fall through. | |
64 case MOJOM_TYPE_DESCRIPTOR_TYPE_UNION: { | |
65 const struct MojomUnionLayout* udata = data_ptr; | |
66 // Unions inside unions may be set to null by setting their pointer to | |
67 // NULL, OR by setting the union's |size| to 0. | |
68 if (!nullable || (udata && udata->size != 0)) { | |
69 return size + MojomUnion_ComputeSerializedSize( | |
70 (const struct MojomTypeDescriptorUnion*)type_desc, | |
71 (const struct MojomUnionLayout*)data); | |
72 } | |
73 break; | |
74 } | |
75 case MOJOM_TYPE_DESCRIPTOR_TYPE_HANDLE: | |
76 case MOJOM_TYPE_DESCRIPTOR_TYPE_INTERFACE: | |
77 case MOJOM_TYPE_DESCRIPTOR_TYPE_POD: | |
78 // We should never end up here. | |
79 assert(false); | |
80 break; | |
81 } | |
82 return size; | |
83 } | |
84 | |
85 static void encode_pointer(union MojomPointer* pointer, uint32_t max_offset) { | |
86 if (pointer->ptr == NULL) { | |
87 pointer->offset = 0; | |
88 } else { | |
89 assert((char*)pointer->ptr > (char*)pointer); | |
90 assert((size_t)((char*)pointer->ptr - (char*)pointer) < max_offset); | |
91 pointer->offset = (char*)(pointer->ptr) - (char*)pointer; | |
92 } | |
93 } | |
94 | |
95 static void decode_pointer(union MojomPointer* pointer) { | |
96 if (pointer->offset == 0) { | |
97 pointer->ptr = NULL; | |
98 } else { | |
99 pointer->ptr = (char*)pointer + pointer->offset; | |
100 } | |
101 } | |
102 | |
103 static void encode_handle(bool nullable, MojoHandle* handle, | |
104 struct MojomHandleBuffer* handles_buffer) { | |
105 assert(handle); | |
106 assert(handles_buffer); | |
107 assert(handles_buffer->handles); | |
108 | |
109 if (*handle == MOJO_HANDLE_INVALID) { | |
110 assert(nullable); | |
111 *handle = kEncodedHandleInvalid; | |
112 } else { | |
113 assert(handles_buffer->num_handles_used < handles_buffer->num_handles); | |
114 | |
115 handles_buffer->handles[handles_buffer->num_handles_used] = *handle; | |
116 *handle = handles_buffer->num_handles_used; | |
117 handles_buffer->num_handles_used++; | |
118 } | |
119 } | |
120 | |
121 // *handle is an index into inout_handles, or is encoded NULL. | |
122 static void decode_handle(MojoHandle* handle, | |
123 MojoHandle inout_handles[], uint32_t in_num_handles) { | |
124 assert(handle); | |
125 assert(inout_handles); | |
126 | |
127 if (*handle == kEncodedHandleInvalid) { | |
128 *handle = MOJO_HANDLE_INVALID; | |
129 } else { | |
130 assert(*handle < in_num_handles); | |
131 MojoHandle index = *handle; | |
132 *handle = inout_handles[index]; | |
133 inout_handles[index] = MOJO_HANDLE_INVALID; | |
134 } | |
135 } | |
136 | |
137 void MojomType_DispatchEncodePointersAndHandles( | |
138 enum MojomTypeDescriptorType in_elem_type, | |
139 const void* in_type_desc, | |
140 bool in_nullable, | |
141 void* inout_buf, | |
142 uint32_t in_buf_size, | |
143 struct MojomHandleBuffer* inout_handles_buffer) { | |
144 assert(inout_buf); | |
145 | |
146 void* union_buf = inout_buf; | |
147 switch (in_elem_type) { | |
148 case MOJOM_TYPE_DESCRIPTOR_TYPE_MAP_PTR: | |
149 case MOJOM_TYPE_DESCRIPTOR_TYPE_STRUCT_PTR: { | |
150 struct MojomStructHeader* inout_struct = | |
151 ((union MojomPointer*)inout_buf)->ptr; | |
152 encode_pointer(inout_buf, in_buf_size); | |
153 if (!in_nullable || inout_struct != NULL) | |
154 MojomStruct_EncodePointersAndHandles( | |
155 (const struct MojomTypeDescriptorStruct*)in_type_desc, | |
156 inout_struct, | |
157 in_buf_size - ((char*)inout_struct - (char*)inout_buf), | |
158 inout_handles_buffer); | |
159 break; | |
160 } | |
161 case MOJOM_TYPE_DESCRIPTOR_TYPE_ARRAY_PTR: { | |
162 struct MojomArrayHeader* inout_array = | |
163 ((union MojomPointer*)inout_buf)->ptr; | |
164 encode_pointer(inout_buf, in_buf_size); | |
165 if (!in_nullable || inout_array != NULL) | |
166 MojomArray_EncodePointersAndHandles( | |
167 (const struct MojomTypeDescriptorArray*)in_type_desc, | |
168 inout_array, | |
169 in_buf_size - ((char*)inout_array - (char*)inout_buf), | |
170 inout_handles_buffer); | |
171 break; | |
172 } | |
173 case MOJOM_TYPE_DESCRIPTOR_TYPE_UNION_PTR: | |
174 union_buf = ((union MojomPointer*)inout_buf)->ptr; | |
175 encode_pointer(inout_buf, in_buf_size); | |
176 // Fall through | |
177 case MOJOM_TYPE_DESCRIPTOR_TYPE_UNION: { | |
178 struct MojomUnionLayout* u_data = union_buf; | |
179 if (!in_nullable || (u_data != NULL && u_data->size != 0)) | |
180 MojomUnion_EncodePointersAndHandles( | |
181 (const struct MojomTypeDescriptorUnion*)in_type_desc, | |
182 inout_buf, | |
183 in_buf_size, | |
184 inout_handles_buffer); | |
185 break; | |
186 } | |
187 case MOJOM_TYPE_DESCRIPTOR_TYPE_HANDLE: | |
188 encode_handle(in_nullable, (MojoHandle*)inout_buf, inout_handles_buffer); | |
189 break; | |
190 case MOJOM_TYPE_DESCRIPTOR_TYPE_INTERFACE: { | |
191 struct MojomInterfaceData* interface = inout_buf; | |
192 encode_handle(in_nullable, &interface->handle, inout_handles_buffer); | |
193 break; | |
194 } | |
195 case MOJOM_TYPE_DESCRIPTOR_TYPE_POD: | |
196 // We shouldn't ever end up here. | |
197 assert(false); | |
198 break; | |
199 } | |
200 } | |
201 | |
202 void MojomType_DispatchDecodePointersAndHandles( | |
203 enum MojomTypeDescriptorType in_elem_type, | |
204 const void* in_type_desc, | |
205 bool in_nullable, | |
206 void* inout_buf, | |
207 uint32_t in_buf_size, | |
208 MojoHandle* inout_handles, | |
209 uint32_t in_num_handles) { | |
210 assert(inout_buf); | |
211 | |
212 void* union_buf = inout_buf; | |
213 switch (in_elem_type) { | |
214 case MOJOM_TYPE_DESCRIPTOR_TYPE_MAP_PTR: | |
215 case MOJOM_TYPE_DESCRIPTOR_TYPE_STRUCT_PTR: { | |
216 decode_pointer(inout_buf); | |
217 struct MojomStructHeader* inout_struct = | |
218 ((union MojomPointer*)inout_buf)->ptr; | |
219 assert(inout_struct == NULL || | |
220 (char*)inout_struct < ((char*)inout_buf) + in_buf_size); | |
221 if (!in_nullable || inout_struct != NULL) | |
222 MojomStruct_DecodePointersAndHandles( | |
223 (const struct MojomTypeDescriptorStruct*)in_type_desc, | |
224 inout_struct, | |
225 in_buf_size - ((char*)inout_struct - (char*)inout_buf), | |
226 inout_handles, | |
227 in_num_handles); | |
228 break; | |
229 } | |
230 case MOJOM_TYPE_DESCRIPTOR_TYPE_ARRAY_PTR: { | |
231 decode_pointer(inout_buf); | |
232 struct MojomArrayHeader* inout_array = | |
233 ((union MojomPointer*)inout_buf)->ptr; | |
234 assert(inout_array == NULL || | |
235 (char*)inout_array < ((char*)inout_buf) + in_buf_size); | |
236 if (!in_nullable || inout_array != NULL) | |
237 MojomArray_DecodePointersAndHandles( | |
238 (const struct MojomTypeDescriptorArray*)in_type_desc, | |
239 inout_array, | |
240 in_buf_size - ((char*)inout_array - (char*)inout_buf), | |
241 inout_handles, | |
242 in_num_handles); | |
243 break; | |
244 } | |
245 case MOJOM_TYPE_DESCRIPTOR_TYPE_UNION_PTR: | |
246 decode_pointer(inout_buf); | |
247 union_buf = ((union MojomPointer*)inout_buf)->ptr; | |
248 assert(union_buf == NULL || | |
249 (char*)union_buf < ((char*)inout_buf) + in_buf_size); | |
250 // Fall through | |
251 case MOJOM_TYPE_DESCRIPTOR_TYPE_UNION: { | |
252 struct MojomUnionLayout* u_data = union_buf; | |
253 if (!in_nullable || (u_data != NULL && u_data->size != 0)) | |
254 MojomUnion_DecodePointersAndHandles( | |
255 (const struct MojomTypeDescriptorUnion*)in_type_desc, | |
256 inout_buf, | |
257 in_buf_size, | |
258 inout_handles, | |
259 in_num_handles); | |
260 break; | |
261 } | |
262 case MOJOM_TYPE_DESCRIPTOR_TYPE_HANDLE: | |
263 decode_handle((MojoHandle*)inout_buf, inout_handles, | |
264 in_num_handles); | |
265 break; | |
266 case MOJOM_TYPE_DESCRIPTOR_TYPE_INTERFACE: { | |
267 struct MojomInterfaceData* interface = inout_buf; | |
268 decode_handle(&interface->handle, inout_handles, | |
269 in_num_handles); | |
270 break; | |
271 } | |
272 case MOJOM_TYPE_DESCRIPTOR_TYPE_POD: | |
273 // We shouldn't ever end up here. | |
274 assert(false); | |
275 break; | |
276 } | |
277 } | |
278 | |
279 // Validates that the offset (|pointer->offset|) points to a new memory region, | |
280 // i.e. one that hasn't been referenced yet. If so, moves the expected offset | |
281 // (for the next pointer) forward. | |
282 static MojomValidationResult validate_pointer( | |
283 const union MojomPointer* pointer, | |
284 size_t max_offset, | |
285 bool is_nullable, | |
286 struct MojomValidationContext* inout_context) { | |
287 // Offset must be <= UINT32_MAX and within range. | |
288 if (pointer->offset > max_offset || pointer->offset > UINT32_MAX) | |
289 return MOJOM_VALIDATION_ILLEGAL_POINTER; | |
290 | |
291 if (pointer->offset != 0) { | |
292 if ((char*)pointer + pointer->offset < inout_context->next_pointer) | |
293 return MOJOM_VALIDATION_ILLEGAL_MEMORY_RANGE; | |
294 | |
295 inout_context->next_pointer = (char*)pointer + pointer->offset; | |
296 } | |
297 | |
298 // Offset must be 8-byte aligned: this check is sufficient, given that all | |
299 // objects are rounded to 8-bytes. | |
300 if ((pointer->offset & 7) != 0) | |
301 return MOJOM_VALIDATION_MISALIGNED_OBJECT; | |
302 | |
303 if (!is_nullable && pointer->offset == 0) | |
304 return MOJOM_VALIDATION_UNEXPECTED_NULL_POINTER; | |
305 | |
306 return MOJOM_VALIDATION_ERROR_NONE; | |
307 } | |
308 | |
309 static MojomValidationResult validate_handle( | |
310 MojoHandle encoded_handle, uint32_t num_handles, bool is_nullable, | |
311 struct MojomValidationContext* inout_context) { | |
312 if (!is_nullable && encoded_handle == kEncodedHandleInvalid) | |
313 return MOJOM_VALIDATION_UNEXPECTED_INVALID_HANDLE; | |
314 | |
315 if (encoded_handle != kEncodedHandleInvalid) { | |
316 if (encoded_handle >= num_handles || | |
317 encoded_handle < inout_context->next_handle_index) | |
318 return MOJOM_VALIDATION_ILLEGAL_HANDLE; | |
319 | |
320 inout_context->next_handle_index = encoded_handle + 1; | |
321 } | |
322 | |
323 return MOJOM_VALIDATION_ERROR_NONE; | |
324 } | |
325 | |
326 MojomValidationResult MojomType_DispatchValidate( | |
327 enum MojomTypeDescriptorType in_elem_type, const void* in_type_desc, | |
328 bool in_nullable, const void* in_buf, uint32_t in_buf_size, | |
329 uint32_t in_num_handles, struct MojomValidationContext* inout_context) { | |
330 assert(in_buf); | |
331 | |
332 struct MojomUnionLayout* union_data = (struct MojomUnionLayout*)in_buf; | |
333 switch (in_elem_type) { | |
334 case MOJOM_TYPE_DESCRIPTOR_TYPE_MAP_PTR: | |
335 case MOJOM_TYPE_DESCRIPTOR_TYPE_STRUCT_PTR: { | |
336 union MojomPointer* pointer = (union MojomPointer*)in_buf; | |
337 MojomValidationResult result = | |
338 validate_pointer(pointer, in_buf_size, in_nullable, inout_context); | |
339 if (result != MOJOM_VALIDATION_ERROR_NONE || pointer->offset == 0) | |
340 return result; | |
341 | |
342 result = MojomStruct_Validate( | |
343 (const struct MojomTypeDescriptorStruct*)in_type_desc, | |
344 (const struct MojomStructHeader*)((char*)in_buf + pointer->offset), | |
345 in_buf_size - pointer->offset, in_num_handles, inout_context); | |
346 | |
347 if (result == MOJOM_VALIDATION_ERROR_NONE && | |
348 in_elem_type == MOJOM_TYPE_DESCRIPTOR_TYPE_MAP_PTR) { | |
349 return MojomMap_Validate( | |
350 (const struct MojomTypeDescriptorStruct*)in_type_desc, | |
351 (const struct MojomStructHeader*)((char*)in_buf + pointer->offset), | |
352 in_buf_size - pointer->offset, in_num_handles, inout_context); | |
353 } | |
354 | |
355 return result; | |
356 } | |
357 case MOJOM_TYPE_DESCRIPTOR_TYPE_ARRAY_PTR: { | |
358 union MojomPointer* pointer = (union MojomPointer*)in_buf; | |
359 MojomValidationResult result = | |
360 validate_pointer(pointer, in_buf_size, in_nullable, inout_context); | |
361 if (result != MOJOM_VALIDATION_ERROR_NONE || pointer->offset == 0) | |
362 return result; | |
363 | |
364 return MojomArray_Validate( | |
365 (const struct MojomTypeDescriptorArray*)in_type_desc, | |
366 (const struct MojomArrayHeader*)((char*)in_buf + pointer->offset), | |
367 in_buf_size - pointer->offset, in_num_handles, inout_context); | |
368 } | |
369 case MOJOM_TYPE_DESCRIPTOR_TYPE_UNION_PTR: { | |
370 union MojomPointer* pointer = (union MojomPointer*)in_buf; | |
371 MojomValidationResult result = | |
372 validate_pointer(pointer, in_buf_size, in_nullable, inout_context); | |
373 if (result != MOJOM_VALIDATION_ERROR_NONE || pointer->offset == 0) | |
374 return result; | |
375 | |
376 // Since this union is a pointer, we update |next_pointer| to be past the | |
377 // union data. | |
378 inout_context->next_pointer += sizeof(struct MojomUnionLayout); | |
379 | |
380 union_data = (struct MojomUnionLayout*)((char*)in_buf + pointer->offset); | |
381 // Fall through. | |
382 } | |
383 case MOJOM_TYPE_DESCRIPTOR_TYPE_UNION: | |
384 if (union_data->size == 0) { | |
385 return in_nullable ? MOJOM_VALIDATION_ERROR_NONE | |
386 : MOJOM_VALIDATION_UNEXPECTED_NULL_UNION; | |
387 } | |
388 | |
389 return MojomUnion_Validate( | |
390 (const struct MojomTypeDescriptorUnion*)in_type_desc, in_nullable, | |
391 union_data, in_buf_size - ((char*)union_data - (char*)in_buf), | |
392 in_num_handles, inout_context); | |
393 case MOJOM_TYPE_DESCRIPTOR_TYPE_HANDLE: | |
394 return validate_handle(*(const MojoHandle*)in_buf, in_num_handles, | |
395 in_nullable, inout_context); | |
396 case MOJOM_TYPE_DESCRIPTOR_TYPE_INTERFACE: | |
397 return validate_handle(((const struct MojomInterfaceData*)in_buf)->handle, | |
398 in_num_handles, in_nullable, inout_context); | |
399 case MOJOM_TYPE_DESCRIPTOR_TYPE_POD: | |
400 break; | |
401 } | |
402 return MOJOM_VALIDATION_ERROR_NONE; | |
403 } | |
404 | |
405 bool MojomType_DispatchDeepCopy(struct MojomBuffer* buffer, | |
406 enum MojomTypeDescriptorType in_elem_type, | |
407 const void* in_type_desc, | |
408 const void* in_data, | |
409 void* out_data) { | |
410 assert(in_data); | |
411 | |
412 const struct MojomUnionLayout* in_union_data = | |
413 (const struct MojomUnionLayout*)in_data; | |
414 struct MojomUnionLayout* out_union_data = (struct MojomUnionLayout*)out_data; | |
415 const union MojomPointer* in_pointer = in_data; | |
416 switch (in_elem_type) { | |
417 case MOJOM_TYPE_DESCRIPTOR_TYPE_MAP_PTR: | |
418 case MOJOM_TYPE_DESCRIPTOR_TYPE_STRUCT_PTR: | |
419 if (in_pointer->ptr == NULL) { | |
420 ((union MojomPointer*)out_data)->ptr = NULL; | |
421 break; | |
422 } | |
423 return MojomStruct_DeepCopy( | |
424 buffer, (const struct MojomTypeDescriptorStruct*)in_type_desc, | |
425 ((union MojomPointer*)in_data)->ptr, | |
426 out_data); | |
427 case MOJOM_TYPE_DESCRIPTOR_TYPE_ARRAY_PTR: | |
428 if (in_pointer->ptr == NULL) { | |
429 ((union MojomPointer*)out_data)->ptr = NULL; | |
430 break; | |
431 } | |
432 return MojomArray_DeepCopy( | |
433 buffer, (const struct MojomTypeDescriptorArray*)in_type_desc, | |
434 ((union MojomPointer*)in_data)->ptr, | |
435 out_data); | |
436 case MOJOM_TYPE_DESCRIPTOR_TYPE_UNION_PTR: | |
437 in_union_data = ((const union MojomPointer*)in_data)->ptr; | |
438 if (in_union_data == NULL) { | |
439 ((union MojomPointer*)out_data)->ptr = NULL; | |
440 break; | |
441 } | |
442 out_union_data = | |
443 MojomBuffer_Allocate(buffer, sizeof(struct MojomUnionLayout)); | |
444 if (out_union_data == NULL) | |
445 return false; | |
446 ((union MojomPointer*)out_data)->ptr = out_union_data; | |
447 // Fall through. | |
448 case MOJOM_TYPE_DESCRIPTOR_TYPE_UNION: | |
449 return MojomUnion_DeepCopy(buffer, | |
450 (const struct MojomTypeDescriptorUnion*)in_type_desc, | |
451 in_union_data, | |
452 out_union_data); | |
453 case MOJOM_TYPE_DESCRIPTOR_TYPE_HANDLE: | |
454 case MOJOM_TYPE_DESCRIPTOR_TYPE_INTERFACE: | |
455 case MOJOM_TYPE_DESCRIPTOR_TYPE_POD: | |
456 break; | |
457 } | |
458 | |
459 return true; | |
460 } | |
OLD | NEW |