| Index: mojo/public/rust/src/bindings/mojom.rs
|
| diff --git a/mojo/public/rust/src/bindings/mojom.rs b/mojo/public/rust/src/bindings/mojom.rs
|
| index 2075dd6e4b3d9093db150e23557b8cccc4972acb..310ff7b3db07b4d9e62f0082e774b9d6a3e90cd7 100644
|
| --- a/mojo/public/rust/src/bindings/mojom.rs
|
| +++ b/mojo/public/rust/src/bindings/mojom.rs
|
| @@ -2,10 +2,9 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| +use bindings::decoding::{Decoder, ValidationError};
|
| use bindings::encoding;
|
| use bindings::encoding::{Bits, Encoder, Context, DATA_HEADER_SIZE, DataHeader, DataHeaderValue};
|
| -use bindings::decoding::Decoder;
|
| -
|
| use bindings::message::MessageHeader;
|
|
|
| use std::cmp::Eq;
|
| @@ -24,6 +23,9 @@ use system::wait_set;
|
| /// The size of a Mojom map plus header in bytes.
|
| const MAP_SIZE: usize = 24;
|
|
|
| +/// The sorted set of versions for a map.
|
| +const MAP_VERSIONS: [(u32, u32); 1] = [(0, MAP_SIZE as u32)];
|
| +
|
| /// The size of a Mojom union in bytes (header included).
|
| pub const UNION_SIZE: usize = 16;
|
|
|
| @@ -62,7 +64,7 @@ pub trait MojomEncodable: Sized {
|
| fn encode(self, encoder: &mut Encoder, context: Context);
|
|
|
| /// Using a decoder, decodes itself out of a byte buffer.
|
| - fn decode(decoder: &mut Decoder, context: Context) -> Self;
|
| + fn decode(decoder: &mut Decoder, context: Context) -> Result<Self, ValidationError>;
|
| }
|
|
|
| /// Whatever implements this trait is a Mojom pointer type which means
|
| @@ -79,7 +81,7 @@ pub trait MojomPointer: MojomEncodable {
|
| fn encode_value(self, encoder: &mut Encoder, context: Context);
|
|
|
| /// Decodes the actual values of the type into the decoder.
|
| - fn decode_value(decoder: &mut Decoder, context: Context) -> Self;
|
| + fn decode_value(decoder: &mut Decoder, context: Context) -> Result<Self, ValidationError>;
|
|
|
| /// Writes a pointer inlined into the current context before calling
|
| /// encode_value.
|
| @@ -92,8 +94,11 @@ pub trait MojomPointer: MojomEncodable {
|
|
|
| /// Reads a pointer inlined into the current context before calling
|
| /// decode_value.
|
| - fn decode_new(decoder: &mut Decoder, _context: Context, pointer: u64) -> Self {
|
| - let new_context = decoder.claim(pointer as usize).unwrap();
|
| + fn decode_new(decoder: &mut Decoder,
|
| + _context: Context,
|
| + pointer: u64)
|
| + -> Result<Self, ValidationError> {
|
| + let new_context = try!(decoder.claim(pointer as usize));
|
| Self::decode_value(decoder, new_context)
|
| }
|
| }
|
| @@ -109,7 +114,7 @@ pub trait MojomUnion: MojomEncodable {
|
| fn encode_value(self, encoder: &mut Encoder, context: Context);
|
|
|
| /// Decode the actual value of the union.
|
| - fn decode_value(decoder: &mut Decoder, context: Context) -> Self;
|
| + fn decode_value(decoder: &mut Decoder, context: Context) -> Result<Self, ValidationError>;
|
|
|
| /// The embed_size for when the union acts as a pointer type.
|
| fn nested_embed_size() -> Bits {
|
| @@ -130,12 +135,18 @@ pub trait MojomUnion: MojomEncodable {
|
| }
|
|
|
| /// The decoding routine for when the union acts as a pointer type.
|
| - fn nested_decode(decoder: &mut Decoder, context: Context) -> Self {
|
| + fn nested_decode(decoder: &mut Decoder, context: Context) -> Result<Self, ValidationError> {
|
| let global_offset = {
|
| let state = decoder.get_mut(&context);
|
| - state.decode_pointer() as usize
|
| + match state.decode_pointer() {
|
| + Some(ptr) => ptr as usize,
|
| + None => return Err(ValidationError::IllegalPointer),
|
| + }
|
| };
|
| - let new_context = decoder.claim(global_offset).unwrap();
|
| + if global_offset == (MOJOM_NULL_POINTER as usize) {
|
| + return Err(ValidationError::UnexpectedNullPointer);
|
| + }
|
| + let new_context = try!(decoder.claim(global_offset as usize));
|
| Self::decode_value(decoder, new_context)
|
| }
|
|
|
| @@ -161,19 +172,19 @@ pub trait MojomUnion: MojomEncodable {
|
| }
|
|
|
| /// The decoding routine for when the union is inlined into the current context.
|
| - fn inline_decode(decoder: &mut Decoder, context: Context) -> Self {
|
| + fn inline_decode(decoder: &mut Decoder, context: Context) -> Result<Self, ValidationError> {
|
| {
|
| let mut state = decoder.get_mut(&context);
|
| state.align_to_byte();
|
| state.align_to_bytes(8);
|
| }
|
| - let value = Self::decode_value(decoder, context.clone());
|
| + let value = try!(Self::decode_value(decoder, context.clone()));
|
| {
|
| let mut state = decoder.get_mut(&context);
|
| state.align_to_byte();
|
| state.align_to_bytes(8);
|
| }
|
| - value
|
| + Ok(value)
|
| }
|
| }
|
|
|
| @@ -243,7 +254,7 @@ pub trait MojomInterfaceRecv: MojomInterface {
|
| type Container: MojomMessageOption;
|
|
|
| /// Tries to read a message from a pipe and decodes it.
|
| - fn recv_response(&self) -> Self::Container {
|
| + fn recv_response(&self) -> Result<Self::Container, ValidationError> {
|
| // TODO(mknyszek): Actually handle errors with reading
|
| let (buffer, handles) = self.pipe().read(mpflags!(Read::None)).unwrap();
|
| Self::Container::decode_message(buffer, handles)
|
| @@ -273,7 +284,9 @@ pub trait MojomStruct: MojomPointer {
|
| }
|
|
|
| /// Decode the type from a byte array and a set of handles.
|
| - fn deserialize(buffer: &mut [u8], handles: Vec<UntypedHandle>) -> Self {
|
| + fn deserialize(buffer: &mut [u8],
|
| + handles: Vec<UntypedHandle>)
|
| + -> Result<Self, ValidationError> {
|
| let mut decoder = Decoder::new(buffer, handles);
|
| Self::decode_new(&mut decoder, Default::default(), 0)
|
| }
|
| @@ -294,14 +307,19 @@ pub trait MojomMessageOption: Sized {
|
| /// Decodes the actual payload of the message.
|
| ///
|
| /// Implemented by a code generator.
|
| - fn decode_payload(name: u32, buffer: &mut [u8], handles: Vec<UntypedHandle>) -> Self;
|
| + fn decode_payload(header: MessageHeader,
|
| + buffer: &mut [u8],
|
| + handles: Vec<UntypedHandle>)
|
| + -> Result<Self, ValidationError>;
|
|
|
| /// Decodes the message header and then the payload, returning a new
|
| /// copy of itself.
|
| - fn decode_message(mut buffer: Vec<u8>, handles: Vec<UntypedHandle>) -> Self {
|
| - let header = MessageHeader::deserialize(&mut buffer[..], Vec::new());
|
| + fn decode_message(mut buffer: Vec<u8>,
|
| + handles: Vec<UntypedHandle>)
|
| + -> Result<Self, ValidationError> {
|
| + let header = try!(MessageHeader::deserialize(&mut buffer[..], Vec::new()));
|
| let payload_buffer = &mut buffer[header.serialized_size(&Default::default())..];
|
| - Self::decode_payload(header.name, payload_buffer, handles)
|
| + Self::decode_payload(header, payload_buffer, handles)
|
| }
|
| }
|
|
|
| @@ -329,9 +347,9 @@ macro_rules! impl_encodable_for_prim {
|
| let mut state = encoder.get_mut(&context);
|
| state.encode(self);
|
| }
|
| - fn decode(decoder: &mut Decoder, context: Context) -> Self {
|
| + fn decode(decoder: &mut Decoder, context: Context) -> Result<Self, ValidationError> {
|
| let mut state = decoder.get_mut(&context);
|
| - state.decode::<Self>()
|
| + Ok(state.decode::<Self>())
|
| }
|
| }
|
| )*
|
| @@ -342,7 +360,7 @@ impl_encodable_for_prim!(i8, i16, i32, i64, u8, u16, u32, u64, f32, f64);
|
|
|
| impl MojomEncodable for bool {
|
| fn mojom_alignment() -> usize {
|
| - panic!("Should never check mojom_alignment of bools (they're bit-aligned)!");
|
| + panic!("Should never check_decode mojom_alignment of bools (they're bit-aligned)!");
|
| }
|
| fn mojom_type() -> MojomType {
|
| MojomType::Simple
|
| @@ -357,9 +375,9 @@ impl MojomEncodable for bool {
|
| let mut state = encoder.get_mut(&context);
|
| state.encode_bool(self);
|
| }
|
| - fn decode(decoder: &mut Decoder, context: Context) -> Self {
|
| + fn decode(decoder: &mut Decoder, context: Context) -> Result<Self, ValidationError> {
|
| let mut state = decoder.get_mut(&context);
|
| - state.decode_bool()
|
| + Ok(state.decode_bool())
|
| }
|
| }
|
|
|
| @@ -394,13 +412,13 @@ impl<T: MojomEncodable> MojomEncodable for Option<T> {
|
| MojomType::Interface => {
|
| state.encode_null_handle();
|
| state.encode(0 as u32);
|
| - },
|
| + }
|
| MojomType::Simple => panic!("Unexpected simple type in Option!"),
|
| }
|
| - },
|
| + }
|
| }
|
| }
|
| - fn decode(decoder: &mut Decoder, context: Context) -> Self {
|
| + fn decode(decoder: &mut Decoder, context: Context) -> Result<Self, ValidationError> {
|
| let skipped = {
|
| let mut state = decoder.get_mut(&context);
|
| match T::mojom_type() {
|
| @@ -412,9 +430,10 @@ impl<T: MojomEncodable> MojomEncodable for Option<T> {
|
| }
|
| };
|
| if skipped {
|
| - None
|
| + Ok(None)
|
| } else {
|
| - Some(T::decode(decoder, context))
|
| + let inner_value = try!(T::decode(decoder, context));
|
| + Ok(Some(inner_value))
|
| }
|
| }
|
| }
|
| @@ -454,18 +473,17 @@ impl<T: MojomEncodable> MojomPointer for Vec<T> {
|
| elem.encode(encoder, context.clone());
|
| }
|
| }
|
| - fn decode_value(decoder: &mut Decoder, context: Context) -> Vec<T> {
|
| - // TODO(mknyszek): Verify elems, bytes, and T::embed_size match
|
| - let (_bytes, elems) = {
|
| + fn decode_value(decoder: &mut Decoder, context: Context) -> Result<Vec<T>, ValidationError> {
|
| + let elems = {
|
| let mut state = decoder.get_mut(&context);
|
| - (state.decode::<u32>(), state.decode::<u32>())
|
| + try!(state.decode_array_header::<T>()).data()
|
| };
|
| let mut value = Vec::with_capacity(elems as usize);
|
| - // TODO(mknyszek): Don't trust elems blindly
|
| for _ in 0..elems {
|
| - value.push(T::decode(decoder, context.clone()));
|
| + let elem = try!(T::decode(decoder, context.clone()));
|
| + value.push(elem);
|
| }
|
| - value
|
| + Ok(value)
|
| }
|
| }
|
|
|
| @@ -483,24 +501,42 @@ macro_rules! impl_encodable_for_boxed_fixed_array {
|
| elem.encode(encoder, context.clone());
|
| }
|
| }
|
| - fn decode_value(decoder: &mut Decoder, context: Context) -> Box<[T; $len]> {
|
| - // TODO(mknyszek): Verify elems, bytes, and T::embed_size match
|
| - let (_bytes, elems) = {
|
| + fn decode_value(decoder: &mut Decoder, context: Context) -> Result<Box<[T; $len]>, ValidationError> {
|
| + let elems = {
|
| let mut state = decoder.get_mut(&context);
|
| - (state.decode::<u32>(), state.decode::<u32>())
|
| + try!(state.decode_array_header::<T>()).data()
|
| };
|
| - assert_eq!(elems, $len);
|
| + if elems != $len {
|
| + return Err(ValidationError::UnexpectedArrayHeader);
|
| + }
|
| let mut array: [T; $len];
|
| + let mut error = None;
|
| unsafe {
|
| // Since we don't force Default to be implemented on Mojom types
|
| // (mainly due to handles) we need to create this array as uninitialized
|
| // and initialize it manually.
|
| array = mem::uninitialized();
|
| + let mut inits = 0;
|
| for elem in &mut array[..] {
|
| - ptr::write(elem, T::decode(decoder, context.clone()));
|
| + match T::decode(decoder, context.clone()) {
|
| + Ok(value) => ptr::write(elem, value),
|
| + Err(err) => {
|
| + error = Some(err);
|
| + break;
|
| + },
|
| + }
|
| + inits += 1;
|
| + }
|
| + // An error occurred, so we need to do some clean-up.
|
| + if inits != $len {
|
| + for i in 0..inits {
|
| + ptr::drop_in_place(&mut array[i] as *mut T);
|
| + }
|
| + mem::forget(array);
|
| + return Err(error.take().expect("Corrupted stack?"));
|
| }
|
| }
|
| - Box::new(array)
|
| + Ok(Box::new(array))
|
| }
|
| }
|
| impl<T: MojomEncodable> MojomEncodable for Box<[T; $len]> {
|
| @@ -527,8 +563,9 @@ impl<T: MojomEncodable> MojomPointer for Box<[T]> {
|
| elem.encode(encoder, context.clone());
|
| }
|
| }
|
| - fn decode_value(decoder: &mut Decoder, context: Context) -> Box<[T]> {
|
| - Vec::<T>::decode_value(decoder, context).into_boxed_slice()
|
| + fn decode_value(decoder: &mut Decoder, context: Context) -> Result<Box<[T]>, ValidationError> {
|
| + let vec_value = try!(Vec::<T>::decode_value(decoder, context));
|
| + Ok(vec_value.into_boxed_slice())
|
| }
|
| }
|
|
|
| @@ -550,19 +587,15 @@ impl MojomPointer for String {
|
| byte.encode(encoder, context.clone());
|
| }
|
| }
|
| - fn decode_value(decoder: &mut Decoder, context: Context) -> String {
|
| + fn decode_value(decoder: &mut Decoder, context: Context) -> Result<String, ValidationError> {
|
| let mut state = decoder.get_mut(&context);
|
| - // TODO(mknyszek): Verify elems, bytes, and T::embed_size match
|
| - let _bytes = state.decode::<u32>();
|
| - let elems = state.decode::<u32>();
|
| + let elems = try!(state.decode_array_header::<u8>()).data();
|
| let mut value = Vec::with_capacity(elems as usize);
|
| - // TODO(mknyszek): Don't trust elems blindly
|
| for _ in 0..elems {
|
| value.push(state.decode::<u8>());
|
| }
|
| match String::from_utf8(value) {
|
| - Ok(string) => string,
|
| - // TODO(mknyszek): Don't panic and return an error
|
| + Ok(string) => Ok(string),
|
| Err(err) => panic!("Error decoding String: {}", err),
|
| }
|
| }
|
| @@ -575,6 +608,19 @@ impl MojomEncodable for String {
|
| }
|
| }
|
|
|
| +/// Helper function to clean up duplicate code in HashMap.
|
| +fn array_claim_and_decode_header<T: MojomEncodable>
|
| + (decoder: &mut Decoder,
|
| + offset: usize)
|
| + -> Result<(Context, usize), ValidationError> {
|
| + let context = try!(decoder.claim(offset));
|
| + let elems = {
|
| + let state = decoder.get_mut(&context);
|
| + try!(state.decode_array_header::<T>()).data()
|
| + };
|
| + Ok((context, elems as usize))
|
| +}
|
| +
|
| impl<K: MojomEncodable + Eq + Hash, V: MojomEncodable> MojomPointer for HashMap<K, V> {
|
| fn header_data(&self) -> DataHeaderValue {
|
| DataHeaderValue::Version(0)
|
| @@ -608,42 +654,45 @@ impl<K: MojomEncodable + Eq + Hash, V: MojomEncodable> MojomPointer for HashMap<
|
| // Encode vals
|
| vals_vec.encode(encoder, context.clone())
|
| }
|
| - fn decode_value(decoder: &mut Decoder, context: Context) -> HashMap<K, V> {
|
| - // TODO(mknyszek): Verify elems, bytes, and T::embed_size match
|
| + fn decode_value(decoder: &mut Decoder,
|
| + context: Context)
|
| + -> Result<HashMap<K, V>, ValidationError> {
|
| let (keys_offset, vals_offset) = {
|
| - let mut state = decoder.get_mut(&context);
|
| - let _bytes = state.decode::<u32>();
|
| - let _version = state.decode::<u32>();
|
| - let keys_offset = state.decode_pointer() as usize;
|
| - let vals_offset = state.decode_pointer() as usize;
|
| - (keys_offset, vals_offset)
|
| - };
|
| - let keys_context = decoder.claim(keys_offset).unwrap();
|
| - let keys_elems = {
|
| - let state = decoder.get_mut(&keys_context);
|
| - let _size_keys = state.decode::<u32>();
|
| - state.decode::<u32>()
|
| + let state = decoder.get_mut(&context);
|
| + try!(state.decode_struct_header(&MAP_VERSIONS));
|
| + // Decode the keys pointer and check for overflow
|
| + let keys_offset = match state.decode_pointer() {
|
| + Some(ptr) => ptr,
|
| + None => return Err(ValidationError::IllegalPointer),
|
| + };
|
| + // Decode the keys pointer and check for overflow
|
| + let vals_offset = match state.decode_pointer() {
|
| + Some(ptr) => ptr,
|
| + None => return Err(ValidationError::IllegalPointer),
|
| + };
|
| + if keys_offset == MOJOM_NULL_POINTER || vals_offset == MOJOM_NULL_POINTER {
|
| + return Err(ValidationError::UnexpectedNullPointer);
|
| + }
|
| + (keys_offset as usize, vals_offset as usize)
|
| };
|
| + let (keys_context, keys_elems) =
|
| + try!(array_claim_and_decode_header::<K>(decoder, keys_offset));
|
| let mut keys_vec: Vec<K> = Vec::with_capacity(keys_elems as usize);
|
| for _ in 0..keys_elems {
|
| - let key = K::decode(decoder, keys_context.clone());
|
| + let key = try!(K::decode(decoder, keys_context.clone()));
|
| keys_vec.push(key);
|
| }
|
| - let vals_context = decoder.claim(vals_offset).unwrap();
|
| - let vals_elems = {
|
| - let state = decoder.get_mut(&vals_context);
|
| - let _size_vals = state.decode::<u32>();
|
| - state.decode::<u32>()
|
| - };
|
| - // TODO(mknyszek): Do a validation error instead
|
| - assert_eq!(keys_elems, vals_elems);
|
| - // TODO(mknyszek): Don't trust elems blindly
|
| + let (vals_context, vals_elems) =
|
| + try!(array_claim_and_decode_header::<V>(decoder, vals_offset));
|
| + if keys_elems != vals_elems {
|
| + return Err(ValidationError::DifferentSizedArraysInMap);
|
| + }
|
| let mut map = HashMap::with_capacity(keys_elems as usize);
|
| for key in keys_vec.into_iter() {
|
| - let val = V::decode(decoder, vals_context.clone());
|
| + let val = try!(V::decode(decoder, vals_context.clone()));
|
| map.insert(key, val);
|
| }
|
| - map
|
| + Ok(map)
|
| }
|
| }
|
|
|
| @@ -677,7 +726,7 @@ impl<K: MojomEncodable + Eq + Hash, V: MojomEncodable> MojomEncodable for HashMa
|
| impl<T: MojomEncodable + CastHandle + Handle> MojomHandle for T {}
|
|
|
| macro_rules! impl_encodable_for_handle {
|
| - ($handle_type:path) => {
|
| + ($handle_t:path) => {
|
| fn mojom_alignment() -> usize {
|
| 4
|
| }
|
| @@ -695,13 +744,12 @@ macro_rules! impl_encodable_for_handle {
|
| let mut state = encoder.get_mut(&context);
|
| state.encode(pos as i32);
|
| }
|
| - fn decode(decoder: &mut Decoder, context: Context) -> $handle_type {
|
| - // TODO(mknyszek): Verify handle index
|
| + fn decode(decoder: &mut Decoder, context: Context) -> Result<$handle_t, ValidationError> {
|
| let handle_index = {
|
| let mut state = decoder.get_mut(&context);
|
| state.decode::<i32>()
|
| };
|
| - decoder.claim_handle::<$handle_type>(handle_index)
|
| + decoder.claim_handle::<$handle_t>(handle_index)
|
| }
|
| }
|
| }
|
|
|