Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(112)

Side by Side Diff: ppapi/native_client/src/shared/ppapi_proxy/object_serialize.cc

Issue 7740013: Cloning a bunch of stuff from the native_client repository at r6528 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2011 The Native Client Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7 #include "native_client/src/shared/ppapi_proxy/object_serialize.h"
8
9 #include <limits>
10 #include <stdio.h>
11 #include <string.h>
12
13
14 #include "native_client/src/include/nacl_macros.h"
15 #include "native_client/src/include/portability_process.h"
16 #ifdef __native_client__
17 #include "native_client/src/shared/ppapi_proxy/plugin_globals.h"
18 #else
19 #include "native_client/src/shared/ppapi_proxy/browser_globals.h"
20 #endif // __native_client__
21 #include "native_client/src/shared/ppapi_proxy/utility.h"
22 #include "ppapi/c/pp_bool.h"
23 #include "ppapi/c/pp_var.h"
24
25 namespace ppapi_proxy {
26
27 namespace {
28
29 // A serialized string consists of a fixed minimum of 8 bytes.
30 static const int kStringFixedBytes = 8;
31 // Followed by a varying number of bytes rounded up to the nearest 8 bytes.
32 static const uint32_t kStringRoundBase = 8;
33
34 } // namespace
35
36 // The basic serialization structure. Used alone for PP_VARTYPE_VOID,
37 // PP_VARTYPE_NULL, and PP_VARTYPE_INT32.
38 struct SerializedFixed {
39 uint32_t type;
40 union {
41 // PP_VARTYPE_BOOLEAN uses this.
42 bool boolean_value;
43 // PP_VARTYPE_INT32 uses this.
44 int32_t int32_value;
45 // PP_VARTYPE_STRING uses this.
46 uint32_t string_length;
47 } u;
48 // The size of this structure should be 8 bytes on all platforms.
49 };
50
51 // The structure used for PP_VARTYPE_DOUBLE.
52 struct SerializedDouble {
53 struct SerializedFixed fixed;
54 double double_value;
55 };
56
57 // The structure used for PP_VARTYPE_STRING.
58
59 struct SerializedString {
60 struct SerializedFixed fixed;
61 char string_bytes[kStringFixedBytes];
62 // Any remaining characters immediately follow, and are padded out to the
63 // nearest multiple of kStringRoundBase bytes.
64 };
65
66 // TODO(sehr): Add a more general compile time assertion package elsewhere.
67 #define ASSERT_TYPE_SIZE(struct_name, struct_size) \
68 int struct_name##_size_should_be_##struct_size[ \
69 sizeof(struct_name) == struct_size ? 1 : 0]
70
71 // Check the wire format sizes for the PP_Var subtypes.
72 ASSERT_TYPE_SIZE(SerializedFixed, 8);
73 ASSERT_TYPE_SIZE(SerializedDouble, 16);
74 ASSERT_TYPE_SIZE(SerializedString, 16);
75
76 //
77 // We currently use offsetof to find the start of string storage.
78 // This avoids the (never seen) case where the compiler inserts in
79 // padding between the struct SerializedFixed fixed header and the
80 // actual payload value in the double, string, and object
81 // serialization variants.
82 //
83 // Untrusted arm toolchain defines an offsetof in stddef.h, so we have
84 // to prefix.
85 //
86 #define NACL_OFFSETOF(pod_t, member) \
87 (static_cast<size_t>(reinterpret_cast<uintptr_t>(&((pod_t *) NULL)->member)))
88
89 namespace {
90
91 // Adding value1 and value2 would overflow a uint32_t.
92 bool AddWouldOverflow(size_t value1, size_t value2) {
93 if (value1 > std::numeric_limits<size_t>::max() - value2) {
94 return true;
95 }
96 size_t sum = value1 + value2;
97 return sum > std::numeric_limits<uint32_t>::max();
98 }
99
100 uint32_t RoundedStringBytes(uint32_t string_length) {
101 // Compute the string length, padded to the nearest multiple of 8.
102 if (AddWouldOverflow(string_length, kStringRoundBase - 1)) {
103 return std::numeric_limits<uint32_t>::max();
104 }
105 return (string_length + (kStringRoundBase - 1)) & ~(kStringRoundBase - 1);
106 }
107
108 uint32_t PpVarSize(const PP_Var& var) {
109 switch (var.type) {
110 case PP_VARTYPE_UNDEFINED:
111 case PP_VARTYPE_NULL:
112 case PP_VARTYPE_BOOL:
113 case PP_VARTYPE_INT32:
114 return sizeof(SerializedFixed);
115 case PP_VARTYPE_DOUBLE:
116 return sizeof(SerializedDouble);
117 case PP_VARTYPE_STRING: {
118 uint32_t string_length;
119 (void) PPBVarInterface()->VarToUtf8(var, &string_length);
120 string_length = RoundedStringBytes(string_length);
121 if (std::numeric_limits<uint32_t>::max() == string_length ||
122 AddWouldOverflow(string_length,
123 NACL_OFFSETOF(SerializedString, string_bytes))) {
124 // Adding the length to the fixed portion would overflow.
125 return 0;
126 }
127 return static_cast<uint32_t>(NACL_OFFSETOF(SerializedString, string_bytes)
128 + string_length);
129 break;
130 }
131 case PP_VARTYPE_OBJECT:
132 case PP_VARTYPE_ARRAY:
133 case PP_VARTYPE_DICTIONARY:
134 NACL_NOTREACHED();
135 break;
136 }
137 // Unrecognized type.
138 return 0;
139 }
140
141 uint32_t PpVarVectorSize(const PP_Var* vars, uint32_t argc) {
142 size_t size = 0;
143
144 for (uint32_t i = 0; i < argc; ++i) {
145 size_t element_size = PpVarSize(vars[i]);
146
147 if (0 == element_size || AddWouldOverflow(size, element_size)) {
148 // Overflow.
149 return 0;
150 }
151 size += element_size;
152 }
153 return static_cast<uint32_t>(size);
154 }
155
156 bool SerializePpVar(const PP_Var* vars,
157 uint32_t argc,
158 char* bytes,
159 uint32_t length) {
160 size_t offset = 0;
161
162 for (uint32_t i = 0; i < argc; ++i) {
163 size_t element_size = PpVarSize(vars[i]);
164 if (0 == element_size || AddWouldOverflow(offset, element_size)) {
165 // Overflow.
166 return false;
167 }
168 if (offset + element_size > length) {
169 // Not enough bytes to put the requested number of PP_Vars.
170 return false;
171 }
172
173 char* p = bytes + offset;
174 SerializedFixed* s = reinterpret_cast<SerializedFixed*>(p);
175 s->type = static_cast<uint32_t>(vars[i].type);
176 // Set the rest of SerializedFixed to 0, in case the following serialization
177 // leaves some of it unchanged.
178 s->u.int32_value = 0;
179
180 switch (vars[i].type) {
181 case PP_VARTYPE_UNDEFINED:
182 case PP_VARTYPE_NULL:
183 element_size = sizeof(SerializedFixed);
184 break;
185 case PP_VARTYPE_BOOL:
186 s->u.boolean_value = static_cast<bool>
187 (PP_TRUE == vars[i].value.as_bool);
188 element_size = sizeof(SerializedFixed);
189 break;
190 case PP_VARTYPE_INT32:
191 s->u.int32_value = vars[i].value.as_int;
192 element_size = sizeof(SerializedFixed);
193 break;
194 case PP_VARTYPE_DOUBLE: {
195 SerializedDouble* sd = reinterpret_cast<SerializedDouble*>(p);
196 sd->double_value = vars[i].value.as_double;
197 element_size = sizeof(SerializedDouble);
198 break;
199 }
200 case PP_VARTYPE_STRING: {
201 uint32_t string_length;
202 const char* str = PPBVarInterface()->VarToUtf8(vars[i], &string_length);
203 SerializedString* ss = reinterpret_cast<SerializedString*>(p);
204 ss->fixed.u.string_length = string_length;
205 memcpy(reinterpret_cast<void*>(ss->string_bytes),
206 reinterpret_cast<const void*>(str),
207 string_length);
208 // Fill padding bytes with zeros.
209 memset(reinterpret_cast<void*>(ss->string_bytes + string_length), 0,
210 RoundedStringBytes(string_length) - string_length);
211 element_size = NACL_OFFSETOF(SerializedString, string_bytes)
212 + RoundedStringBytes(string_length);
213 break;
214 }
215 case PP_VARTYPE_OBJECT:
216 case PP_VARTYPE_ARRAY:
217 case PP_VARTYPE_DICTIONARY:
218 NACL_NOTREACHED();
219 default:
220 return false;
221 }
222 offset += element_size;
223 }
224 return true;
225 }
226
227
228 //
229 // Compute how many bytes does the string object to be deserialzed use
230 // in the serialized format. On error, return
231 // std::numeric_limits<uint32_t>::max(). This means we cannot handle
232 // 2**32-1 byte strings.
233 //
234 uint32_t DeserializeStringSize(char* p, uint32_t length) {
235 // zero length strings are okay... but not shorter
236 if (length < NACL_OFFSETOF(SerializedString, string_bytes)) {
237 return std::numeric_limits<uint32_t>::max();
238 }
239 SerializedString* ss = reinterpret_cast<SerializedString*>(p);
240 if (PP_VARTYPE_STRING != ss->fixed.type) {
241 return std::numeric_limits<uint32_t>::max();
242 }
243 uint32_t string_length = ss->fixed.u.string_length;
244 string_length = RoundedStringBytes(string_length);
245 if (std::numeric_limits<uint32_t>::max() == string_length) {
246 return std::numeric_limits<uint32_t>::max();
247 }
248 if (AddWouldOverflow(NACL_OFFSETOF(SerializedString, string_bytes),
249 string_length)) {
250 return std::numeric_limits<uint32_t>::max();
251 }
252 uint32_t total_bytes = NACL_OFFSETOF(SerializedString, string_bytes)
253 + string_length;
254 if (total_bytes > length) {
255 return std::numeric_limits<uint32_t>::max();
256 }
257 return total_bytes;
258 }
259
260
261 //
262 // Compute the number of bytes that will be consumed by the next
263 // object, based on its type. If there aren't enough bytes,
264 // std::numeric_limits<uint32_t>::max() will be returned.
265 //
266 // If element_type_ptr is non-NULL, then the next element's
267 // (purported) type will be filled in. Whether this occurs when there
268 // is an error (e.g., not enough data) is not defined, i.e., only rely
269 // on it when there's no error.
270 //
271 uint32_t DeserializePpVarSize(char* p,
272 uint32_t length,
273 PP_VarType* element_type_ptr) {
274 SerializedFixed* sfp;
275 if (length < sizeof *sfp) {
276 return std::numeric_limits<uint32_t>::max();
277 }
278 sfp = reinterpret_cast<SerializedFixed*>(p);
279 uint32_t expected_element_size = 0;
280 //
281 // Setting this to zero handles the "default" case. That can occur
282 // because sfp->type can originate from untrusted code, and so the
283 // value could actually be outside of the PP_VarType enumeration
284 // range. If we hit one of the cases below, then
285 // expected_element_size will be bounded away from zero.
286 //
287 switch (static_cast<PP_VarType>(sfp->type)) {
288 case PP_VARTYPE_UNDEFINED:
289 case PP_VARTYPE_NULL:
290 case PP_VARTYPE_BOOL:
291 case PP_VARTYPE_INT32:
292 expected_element_size = sizeof(SerializedFixed);
293 break;
294 case PP_VARTYPE_DOUBLE:
295 expected_element_size = sizeof(SerializedDouble);
296 break;
297 case PP_VARTYPE_STRING:
298 expected_element_size = DeserializeStringSize(p, length);
299 if (std::numeric_limits<uint32_t>::max() == expected_element_size) {
300 return std::numeric_limits<uint32_t>::max();
301 }
302 break;
303 // NB: No default case to trigger -Wswitch-enum, so changes to
304 // PP_VarType w/o corresponding changes here will cause a
305 // compile-time error.
306 case PP_VARTYPE_OBJECT:
307 case PP_VARTYPE_ARRAY:
308 case PP_VARTYPE_DICTIONARY:
309 NACL_NOTREACHED();
310 break;
311 }
312 if (length < expected_element_size) {
313 return std::numeric_limits<uint32_t>::max();
314 }
315 if (NULL != element_type_ptr) {
316 *element_type_ptr = static_cast<PP_VarType>(sfp->type);
317 }
318 return expected_element_size;
319 }
320
321
322 //
323 // This should be invoked only if DeserializePpVarSize succeeds, i.e.,
324 // there are enough bytes at p.
325 //
326 bool DeserializeString(char* p,
327 PP_Var* var,
328 NaClSrpcChannel* channel) {
329 SerializedString* ss = reinterpret_cast<SerializedString*>(p);
330 uint32_t string_length = ss->fixed.u.string_length;
331 // VarFromUtf8 creates a buffer of size string_length using the browser-side
332 // memory allocation function, and copies string_length bytes from
333 // ss->string_bytes in to that buffer. The ref count of the returned var is
334 // 1.
335 *var = PPBVarInterface()->VarFromUtf8(LookupModuleIdForSrpcChannel(channel),
336 ss->string_bytes,
337 string_length);
338 return true;
339 }
340
341 bool DeserializePpVar(NaClSrpcChannel* channel,
342 char* bytes,
343 uint32_t length,
344 PP_Var* vars,
345 uint32_t argc) {
346 char* p = bytes;
347
348 for (uint32_t i = 0; i < argc; ++i) {
349 PP_VarType element_type;
350 uint32_t element_size = DeserializePpVarSize(p, length, &element_type);
351 if (std::numeric_limits<uint32_t>::max() == element_size) {
352 return false;
353 }
354 SerializedFixed* s = reinterpret_cast<SerializedFixed*>(p);
355
356 vars[i].type = element_type;
357 switch (element_type) {
358 case PP_VARTYPE_UNDEFINED:
359 case PP_VARTYPE_NULL:
360 break;
361 case PP_VARTYPE_BOOL:
362 vars[i].value.as_bool = static_cast<PP_Bool>(s->u.boolean_value);
363 break;
364 case PP_VARTYPE_INT32:
365 vars[i].value.as_int = s->u.int32_value;
366 break;
367 case PP_VARTYPE_DOUBLE: {
368 SerializedDouble* sd = reinterpret_cast<SerializedDouble*>(p);
369 vars[i].value.as_double = sd->double_value;
370 break;
371 }
372 case PP_VARTYPE_STRING:
373 if (!DeserializeString(p, &vars[i], channel)) {
374 return false;
375 }
376 break;
377 case PP_VARTYPE_OBJECT:
378 case PP_VARTYPE_ARRAY:
379 case PP_VARTYPE_DICTIONARY:
380 NACL_NOTREACHED();
381 default:
382 return false;
383 }
384 p += element_size;
385 length -= element_size;
386 }
387 return true;
388 }
389
390 } // namespace
391
392 bool SerializeTo(const PP_Var* var, char* bytes, uint32_t* length) {
393 if (bytes == NULL || length == NULL) {
394 return false;
395 }
396 // Compute the size of the serialized form. Zero indicates error.
397 uint32_t tmp_length = PpVarVectorSize(var, 1);
398 if (0 == tmp_length || tmp_length > *length) {
399 return false;
400 }
401 // Serialize the var.
402 if (!SerializePpVar(var, 1, bytes, tmp_length)) {
403 return false;
404 }
405 // Return success.
406 *length = tmp_length;
407 return true;
408 }
409
410 char* Serialize(const PP_Var* vars, uint32_t argc, uint32_t* length) {
411 // Length needs to be set.
412 if (NULL == length) {
413 return NULL;
414 }
415 // No need to do anything if there are no vars to serialize.
416 if (0 == argc) {
417 *length = 0;
418 return NULL;
419 }
420 // Report an error if no vars are passed but argc > 0.
421 if (NULL == vars) {
422 return NULL;
423 }
424 // Compute the size of the buffer. Zero indicates error.
425 uint32_t tmp_length = PpVarVectorSize(vars, argc);
426 if (0 == tmp_length || tmp_length > *length) {
427 return NULL;
428 }
429 // Allocate the buffer, if the client didn't pass one.
430 char* bytes = new char[tmp_length];
431 if (NULL == bytes) {
432 return NULL;
433 }
434 // Serialize the vars.
435 if (!SerializePpVar(vars, argc, bytes, tmp_length)) {
436 delete[] bytes;
437 return NULL;
438 }
439 // Return success.
440 *length = tmp_length;
441 return bytes;
442 }
443
444 bool DeserializeTo(NaClSrpcChannel* channel,
445 char* bytes,
446 uint32_t length,
447 uint32_t argc,
448 PP_Var* vars) {
449 // Deserializing a zero-length vector is trivially done.
450 if (0 == argc) {
451 return true;
452 }
453 // Otherwise, there must be some input bytes to get from.
454 if (NULL == bytes || 0 == length) {
455 return false;
456 }
457 // And there has to be a valid address to deserialize to.
458 if (NULL == vars) {
459 return false;
460 }
461 // Read the serialized PP_Vars into the allocated memory.
462 if (!DeserializePpVar(channel, bytes, length, vars, argc)) {
463 return false;
464 }
465 return true;
466 }
467
468 } // namespace ppapi_proxy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698