diff --git a/components/derive_common/cg.rs b/components/derive_common/cg.rs index c1b6588c749..c51c0d7750b 100644 --- a/components/derive_common/cg.rs +++ b/components/derive_common/cg.rs @@ -85,9 +85,22 @@ pub fn add_predicate(where_clause: &mut Option, pred: WherePre .push(pred); } -pub fn fmap_match(input: &DeriveInput, bind_style: BindStyle, mut f: F) -> TokenStream +pub fn fmap_match(input: &DeriveInput, bind_style: BindStyle, f: F) -> TokenStream where - F: FnMut(BindingInfo) -> TokenStream, + F: FnMut(&BindingInfo) -> TokenStream, +{ + fmap2_match(input, bind_style, f, |_| None) +} + +pub fn fmap2_match( + input: &DeriveInput, + bind_style: BindStyle, + mut f: F, + mut g: G, +) -> TokenStream +where + F: FnMut(&BindingInfo) -> TokenStream, + G: FnMut(&BindingInfo) -> Option, { let mut s = synstructure::Structure::new(input); s.variants_mut().iter_mut().for_each(|v| { @@ -95,12 +108,20 @@ where }); s.each_variant(|variant| { let (mapped, mapped_fields) = value(variant, "mapped"); - let fields_pairs = variant.bindings().iter().zip(mapped_fields); + let fields_pairs = variant.bindings().iter().zip(mapped_fields.iter()); let mut computations = quote!(); computations.append_all(fields_pairs.map(|(field, mapped_field)| { - let expr = f(field.clone()); + let expr = f(field); quote! { let #mapped_field = #expr; } })); + computations.append_all( + mapped_fields + .iter() + .map(|mapped_field| match g(mapped_field) { + Some(expr) => quote! { let #mapped_field = #expr; }, + None => quote!(), + }), + ); computations.append_all(mapped); Some(computations) }) diff --git a/components/style/gecko/url.rs b/components/style/gecko/url.rs index 27f3c60884c..678adb39b09 100644 --- a/components/style/gecko/url.rs +++ b/components/style/gecko/url.rs @@ -18,7 +18,7 @@ use std::fmt::{self, Write}; use std::mem::ManuallyDrop; use std::sync::RwLock; use style_traits::{CssWriter, ParseError, ToCss}; -use to_shmem::{SharedMemoryBuilder, ToShmem}; +use to_shmem::{self, SharedMemoryBuilder, ToShmem}; /// A CSS url() value for gecko. #[css(function = "url")] @@ -241,11 +241,11 @@ impl LoadDataSource { } impl ToShmem for LoadDataSource { - fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> ManuallyDrop { - ManuallyDrop::new(match self { + fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> to_shmem::Result { + Ok(ManuallyDrop::new(match self { LoadDataSource::Owned(..) => LoadDataSource::Lazy, LoadDataSource::Lazy => LoadDataSource::Lazy, - }) + })) } } diff --git a/components/style/gecko_string_cache/mod.rs b/components/style/gecko_string_cache/mod.rs index b9e3a0c608a..e9208a5e32e 100644 --- a/components/style/gecko_string_cache/mod.rs +++ b/components/style/gecko_string_cache/mod.rs @@ -3,7 +3,6 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #![allow(unsafe_code)] - // This is needed for the constants in atom_macro.rs, because we have some // atoms whose names differ only by case, e.g. datetime and dateTime. #![allow(non_upper_case_globals)] @@ -30,7 +29,7 @@ use std::num::NonZeroUsize; use std::ops::Deref; use std::{slice, str}; use style_traits::SpecifiedValueInfo; -use to_shmem::{SharedMemoryBuilder, ToShmem}; +use to_shmem::{self, SharedMemoryBuilder, ToShmem}; #[macro_use] #[allow(improper_ctypes, non_camel_case_types, missing_docs)] @@ -132,14 +131,15 @@ impl Borrow for Atom { } impl ToShmem for Atom { - fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> ManuallyDrop { - assert!( - self.is_static(), - "ToShmem failed for Atom: must be a static atom: {}", - self - ); + fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> to_shmem::Result { + if !self.is_static() { + return Err(format!( + "ToShmem failed for Atom: must be a static atom: {}", + self + )); + } - ManuallyDrop::new(Atom(self.0)) + Ok(ManuallyDrop::new(Atom(self.0))) } } diff --git a/components/style/shared_lock.rs b/components/style/shared_lock.rs index d46370952d3..107fd6d7103 100644 --- a/components/style/shared_lock.rs +++ b/components/style/shared_lock.rs @@ -258,20 +258,20 @@ impl Locked { #[cfg(feature = "gecko")] impl ToShmem for Locked { - fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> ManuallyDrop { + fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> to_shmem::Result { let guard = self.shared_lock.read(); - ManuallyDrop::new(Locked { + Ok(ManuallyDrop::new(Locked { shared_lock: SharedRwLock::read_only(), data: UnsafeCell::new(ManuallyDrop::into_inner( - self.read_with(&guard).to_shmem(builder), + self.read_with(&guard).to_shmem(builder)?, )), - }) + })) } } #[cfg(feature = "servo")] impl ToShmem for Locked { - fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> ManuallyDrop { + fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> to_shmem::Result { panic!("ToShmem not supported in Servo currently") } } diff --git a/components/style/stylesheets/import_rule.rs b/components/style/stylesheets/import_rule.rs index 982572673a9..5efae0a3ee5 100644 --- a/components/style/stylesheets/import_rule.rs +++ b/components/style/stylesheets/import_rule.rs @@ -15,9 +15,8 @@ use crate::stylesheets::{CssRule, Origin, StylesheetInDocument}; use crate::values::CssUrl; use cssparser::SourceLocation; use std::fmt::{self, Write}; -use std::mem::ManuallyDrop; use style_traits::{CssWriter, ToCss}; -use to_shmem::{SharedMemoryBuilder, ToShmem}; +use to_shmem::{self, SharedMemoryBuilder, ToShmem}; /// With asynchronous stylesheet parsing, we can't synchronously create a /// GeckoStyleSheet. So we use this placeholder instead. @@ -184,8 +183,10 @@ pub struct ImportRule { } impl ToShmem for ImportRule { - fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> ManuallyDrop { - panic!("ToShmem failed for ImportRule: cannot handle imported style sheets") + fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> to_shmem::Result { + Err(String::from( + "ToShmem failed for ImportRule: cannot handle imported style sheets", + )) } } diff --git a/components/style/stylesheets/mod.rs b/components/style/stylesheets/mod.rs index daf97f20e3c..12ba46b3e06 100644 --- a/components/style/stylesheets/mod.rs +++ b/components/style/stylesheets/mod.rs @@ -40,7 +40,7 @@ use std::fmt; use std::mem::{self, ManuallyDrop}; use style_traits::ParsingMode; #[cfg(feature = "gecko")] -use to_shmem::{SharedMemoryBuilder, ToShmem}; +use to_shmem::{self, SharedMemoryBuilder, ToShmem}; pub use self::counter_style_rule::CounterStyleRule; pub use self::document_rule::DocumentRule; @@ -117,20 +117,25 @@ impl Drop for UrlExtraData { #[cfg(feature = "gecko")] impl ToShmem for UrlExtraData { - fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> ManuallyDrop { + fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> to_shmem::Result { if self.0 & 1 == 0 { let shared_extra_datas = unsafe { &structs::URLExtraData_sShared }; let self_ptr = self.as_ref() as *const _ as *mut _; let sheet_id = shared_extra_datas .iter() - .position(|r| r.mRawPtr == self_ptr) - .expect( - "ToShmem failed for UrlExtraData: expected sheet's URLExtraData to be in \ - URLExtraData::sShared", - ); - ManuallyDrop::new(UrlExtraData((sheet_id << 1) | 1)) + .position(|r| r.mRawPtr == self_ptr); + let sheet_id = match sheet_id { + Some(id) => id, + None => { + return Err(String::from( + "ToShmem failed for UrlExtraData: expected sheet's URLExtraData to be in \ + URLExtraData::sShared", + )); + }, + }; + Ok(ManuallyDrop::new(UrlExtraData((sheet_id << 1) | 1))) } else { - ManuallyDrop::new(UrlExtraData(self.0)) + Ok(ManuallyDrop::new(UrlExtraData(self.0))) } } } diff --git a/components/style/values/computed/font.rs b/components/style/values/computed/font.rs index 0f821123c20..ed00f42d678 100644 --- a/components/style/values/computed/font.rs +++ b/components/style/values/computed/font.rs @@ -32,7 +32,7 @@ use std::mem::{self, ManuallyDrop}; use std::slice; use style_traits::{CssWriter, ParseError, ToCss}; #[cfg(feature = "gecko")] -use to_shmem::{SharedMemoryBuilder, ToShmem}; +use to_shmem::{self, SharedMemoryBuilder, ToShmem}; pub use crate::values::computed::Length as MozScriptMinSize; pub use crate::values::specified::font::{FontSynthesis, MozScriptSizeMultiplier}; @@ -466,19 +466,20 @@ pub enum FontFamilyList { #[cfg(feature = "gecko")] impl ToShmem for FontFamilyList { - fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> ManuallyDrop { + fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> to_shmem::Result { // In practice, the only SharedFontList objects we create from shared // style sheets are ones with a single generic entry. - ManuallyDrop::new(match *self { + Ok(ManuallyDrop::new(match *self { FontFamilyList::SharedFontList(ref r) => { - assert!( - r.mNames.len() == 1 && r.mNames[0].mName.mRawPtr.is_null(), - "ToShmem failed for FontFamilyList: cannot handle non-generic families", - ); + if !(r.mNames.len() == 1 && r.mNames[0].mName.mRawPtr.is_null()) { + return Err(String::from( + "ToShmem failed for FontFamilyList: cannot handle non-generic families", + )); + } FontFamilyList::Generic(r.mNames[0].mGeneric) }, FontFamilyList::Generic(t) => FontFamilyList::Generic(t), - }) + })) } } diff --git a/components/style_traits/owned_slice.rs b/components/style_traits/owned_slice.rs index bbce7065196..f6068365360 100644 --- a/components/style_traits/owned_slice.rs +++ b/components/style_traits/owned_slice.rs @@ -13,7 +13,7 @@ use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::ptr::NonNull; use std::{fmt, iter, mem, slice}; -use to_shmem::{SharedMemoryBuilder, ToShmem}; +use to_shmem::{self, SharedMemoryBuilder, ToShmem}; /// A struct that basically replaces a `Box<[T]>`, but which cbindgen can /// understand. @@ -159,10 +159,10 @@ impl MallocSizeOf for OwnedSlice { } impl ToShmem for OwnedSlice { - fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> mem::ManuallyDrop { + fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> to_shmem::Result { unsafe { - let dest = to_shmem::to_shmem_slice(self.iter(), builder); - mem::ManuallyDrop::new(Self::from(Box::from_raw(dest))) + let dest = to_shmem::to_shmem_slice(self.iter(), builder)?; + Ok(mem::ManuallyDrop::new(Self::from(Box::from_raw(dest)))) } } } diff --git a/components/to_shmem/lib.rs b/components/to_shmem/lib.rs index 22b86087bfd..47dc8d17eff 100644 --- a/components/to_shmem/lib.rs +++ b/components/to_shmem/lib.rs @@ -42,6 +42,11 @@ use std::slice; use std::str; use thin_slice::ThinBoxedSlice; +/// Result type for ToShmem::to_shmem. +/// +/// The String is an error message describing why the call failed. +pub type Result = std::result::Result, String>; + // Various pointer arithmetic functions in this file can be replaced with // functions on `Layout` once they have stabilized: // @@ -114,13 +119,13 @@ impl SharedMemoryBuilder { /// a shared memory buffer by calling ToShmem::to_shmem on it. /// /// Panics if there is insufficient space in the buffer. - pub fn write(&mut self, value: &T) -> *mut T { + pub fn write(&mut self, value: &T) -> std::result::Result<*mut T, String> { // Reserve space for the value. let dest: *mut T = self.alloc_value(); // Make a clone of the value with all of its heap allocations // placed in the shared memory buffer. - let value = value.to_shmem(self); + let value = value.to_shmem(self)?; unsafe { // Copy the value into the buffer. @@ -128,7 +133,7 @@ impl SharedMemoryBuilder { } // Return a pointer to the shared value. - dest + Ok(dest) } /// Reserves space in the shared memory buffer to fit a value of type T, @@ -190,7 +195,10 @@ pub trait ToShmem: Sized { /// /// The return type is wrapped in ManuallyDrop to make it harder to /// accidentally invoke the destructor of the value that is produced. - fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> ManuallyDrop; + /// + /// Returns a Result so that we can gracefully recover from unexpected + /// content. + fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> Result; } #[macro_export] @@ -201,8 +209,8 @@ macro_rules! impl_trivial_to_shmem { fn to_shmem( &self, _builder: &mut $crate::SharedMemoryBuilder, - ) -> ::std::mem::ManuallyDrop { - ::std::mem::ManuallyDrop::new(*self) + ) -> $crate::Result { + $crate::Result::Ok(::std::mem::ManuallyDrop::new(*self)) } } )* @@ -231,58 +239,60 @@ impl_trivial_to_shmem!(cssparser::SourceLocation); impl_trivial_to_shmem!(cssparser::TokenSerializationType); impl ToShmem for PhantomData { - fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> ManuallyDrop { - ManuallyDrop::new(*self) + fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> Result { + Ok(ManuallyDrop::new(*self)) } } impl ToShmem for Range { - fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> ManuallyDrop { - ManuallyDrop::new(Range { - start: ManuallyDrop::into_inner(self.start.to_shmem(builder)), - end: ManuallyDrop::into_inner(self.end.to_shmem(builder)), - }) + fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> Result { + Ok(ManuallyDrop::new(Range { + start: ManuallyDrop::into_inner(self.start.to_shmem(builder)?), + end: ManuallyDrop::into_inner(self.end.to_shmem(builder)?), + })) } } impl ToShmem for cssparser::UnicodeRange { - fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> ManuallyDrop { - ManuallyDrop::new(cssparser::UnicodeRange { + fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> Result { + Ok(ManuallyDrop::new(cssparser::UnicodeRange { start: self.start, end: self.end, - }) + })) } } impl ToShmem for (T, U) { - fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> ManuallyDrop { - ManuallyDrop::new(( - ManuallyDrop::into_inner(self.0.to_shmem(builder)), - ManuallyDrop::into_inner(self.1.to_shmem(builder)), - )) + fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> Result { + Ok(ManuallyDrop::new(( + ManuallyDrop::into_inner(self.0.to_shmem(builder)?), + ManuallyDrop::into_inner(self.1.to_shmem(builder)?), + ))) } } impl ToShmem for Wrapping { - fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> ManuallyDrop { - ManuallyDrop::new(Wrapping(ManuallyDrop::into_inner(self.0.to_shmem(builder)))) + fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> Result { + Ok(ManuallyDrop::new(Wrapping(ManuallyDrop::into_inner( + self.0.to_shmem(builder)?, + )))) } } impl ToShmem for Box { - fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> ManuallyDrop { + fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> Result { // Reserve space for the boxed value. let dest: *mut T = builder.alloc_value(); // Make a clone of the boxed value with all of its heap allocations // placed in the shared memory buffer. - let value = (**self).to_shmem(builder); + let value = (**self).to_shmem(builder)?; unsafe { // Copy the value into the buffer. ptr::write(dest, ManuallyDrop::into_inner(value)); - ManuallyDrop::new(Box::from_raw(dest)) + Ok(ManuallyDrop::new(Box::from_raw(dest))) } } } @@ -293,7 +303,7 @@ unsafe fn to_shmem_slice_ptr<'a, T, I>( src: I, dest: *mut T, builder: &mut SharedMemoryBuilder, -) -> *mut [T] +) -> std::result::Result<*mut [T], String> where T: 'a + ToShmem, I: ExactSizeIterator, @@ -303,15 +313,18 @@ where // Make a clone of each element from the iterator with its own heap // allocations placed in the buffer, and copy that clone into the buffer. for (src, dest) in src.zip(dest.iter_mut()) { - ptr::write(dest, ManuallyDrop::into_inner(src.to_shmem(builder))); + ptr::write(dest, ManuallyDrop::into_inner(src.to_shmem(builder)?)); } - dest + Ok(dest) } /// Writes all the items in `src` into a slice in the shared memory buffer and /// returns a pointer to the slice. -pub unsafe fn to_shmem_slice<'a, T, I>(src: I, builder: &mut SharedMemoryBuilder) -> *mut [T] +pub unsafe fn to_shmem_slice<'a, T, I>( + src: I, + builder: &mut SharedMemoryBuilder, +) -> std::result::Result<*mut [T], String> where T: 'a + ToShmem, I: ExactSizeIterator, @@ -321,16 +334,16 @@ where } impl ToShmem for Box<[T]> { - fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> ManuallyDrop { + fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> Result { unsafe { - let dest = to_shmem_slice(self.iter(), builder); - ManuallyDrop::new(Box::from_raw(dest)) + let dest = to_shmem_slice(self.iter(), builder)?; + Ok(ManuallyDrop::new(Box::from_raw(dest))) } } } impl ToShmem for ThinBoxedSlice { - fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> ManuallyDrop { + fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> Result { // We could support this if we needed but in practice we will never // need to handle such big ThinBoxedSlices. assert!( @@ -340,14 +353,14 @@ impl ToShmem for ThinBoxedSlice { ); unsafe { - let dest = to_shmem_slice(self.iter(), builder); - ManuallyDrop::new(ThinBoxedSlice::from_raw(dest)) + let dest = to_shmem_slice(self.iter(), builder)?; + Ok(ManuallyDrop::new(ThinBoxedSlice::from_raw(dest))) } } } impl ToShmem for Box { - fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> ManuallyDrop { + fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> Result { // Reserve space for the string bytes. let dest: *mut u8 = builder.alloc_array(self.len()); @@ -355,15 +368,15 @@ impl ToShmem for Box { // Copy the value into the buffer. ptr::copy(self.as_ptr(), dest, self.len()); - ManuallyDrop::new(Box::from_raw(str::from_utf8_unchecked_mut( - slice::from_raw_parts_mut(dest, self.len()), + Ok(ManuallyDrop::new(Box::from_raw( + str::from_utf8_unchecked_mut(slice::from_raw_parts_mut(dest, self.len())), ))) } } } impl ToShmem for String { - fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> ManuallyDrop { + fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> Result { // Reserve space for the string bytes. let dest: *mut u8 = builder.alloc_array(self.len()); @@ -371,13 +384,17 @@ impl ToShmem for String { // Copy the value into the buffer. ptr::copy(self.as_ptr(), dest, self.len()); - ManuallyDrop::new(String::from_raw_parts(dest, self.len(), self.len())) + Ok(ManuallyDrop::new(String::from_raw_parts( + dest, + self.len(), + self.len(), + ))) } } } impl ToShmem for CString { - fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> ManuallyDrop { + fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> Result { let len = self.as_bytes_with_nul().len(); // Reserve space for the string bytes. @@ -387,53 +404,55 @@ impl ToShmem for CString { // Copy the value into the buffer. ptr::copy(self.as_ptr(), dest, len); - ManuallyDrop::new(CString::from_raw(dest)) + Ok(ManuallyDrop::new(CString::from_raw(dest))) } } } impl ToShmem for Vec { - fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> ManuallyDrop { + fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> Result { unsafe { - let dest = to_shmem_slice(self.iter(), builder) as *mut T; + let dest = to_shmem_slice(self.iter(), builder)? as *mut T; let dest_vec = Vec::from_raw_parts(dest, self.len(), self.len()); - ManuallyDrop::new(dest_vec) + Ok(ManuallyDrop::new(dest_vec)) } } } impl> ToShmem for SmallVec { - fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> ManuallyDrop { + fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> Result { let dest_vec = unsafe { if self.spilled() { // Place the items in a separate allocation in the shared memory // buffer. - let dest = to_shmem_slice(self.iter(), builder) as *mut T; + let dest = to_shmem_slice(self.iter(), builder)? as *mut T; SmallVec::from_raw_parts(dest, self.len(), self.len()) } else { // Place the items inline. let mut s = SmallVec::new(); - to_shmem_slice_ptr(self.iter(), s.as_mut_ptr(), builder); + to_shmem_slice_ptr(self.iter(), s.as_mut_ptr(), builder)?; s.set_len(self.len()); s } }; - ManuallyDrop::new(dest_vec) + Ok(ManuallyDrop::new(dest_vec)) } } impl ToShmem for Option { - fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> ManuallyDrop { - ManuallyDrop::new( - self.as_ref() - .map(|v| ManuallyDrop::into_inner(v.to_shmem(builder))), - ) + fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> Result { + let v = match self { + Some(v) => Some(ManuallyDrop::into_inner(v.to_shmem(builder)?)), + None => None, + }; + + Ok(ManuallyDrop::new(v)) } } impl ToShmem for Arc { - fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> ManuallyDrop { + fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> Result { // Assert that we don't encounter any shared references to values we // don't expect. Those we expect are those noted by calling // add_allowed_duplication_type, and should be types where we're fine @@ -453,7 +472,7 @@ impl ToShmem for Arc { // Make a clone of the Arc-owned value with all of its heap allocations // placed in the shared memory buffer. - let value = (**self).to_shmem(builder); + let value = (**self).to_shmem(builder)?; // Create a new Arc with the shared value and have it place its // ArcInner in the shared memory buffer. @@ -466,13 +485,13 @@ impl ToShmem for Arc { #[cfg(debug_assertions)] builder.shared_values.insert(self.heap_ptr()); - ManuallyDrop::new(static_arc) + Ok(ManuallyDrop::new(static_arc)) } } } impl ToShmem for ThinArc { - fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> ManuallyDrop { + fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> Result { // We don't currently have any shared ThinArc values in stylesheets, // so don't support them for now. #[cfg(debug_assertions)] @@ -484,8 +503,11 @@ impl ToShmem for ThinArc { // Make a clone of the Arc-owned header and slice values with all of // their heap allocations placed in the shared memory buffer. - let header = self.header.header.to_shmem(builder); - let values: Vec> = self.slice.iter().map(|v| v.to_shmem(builder)).collect(); + let header = self.header.header.to_shmem(builder)?; + let mut values = Vec::with_capacity(self.slice.len()); + for v in self.slice.iter() { + values.push(v.to_shmem(builder)?); + } // Create a new ThinArc with the shared value and have it place // its ArcInner in the shared memory buffer. @@ -499,13 +521,13 @@ impl ToShmem for ThinArc { #[cfg(debug_assertions)] builder.shared_values.insert(self.heap_ptr()); - ManuallyDrop::new(static_arc) + Ok(ManuallyDrop::new(static_arc)) } } } impl ToShmem for SmallBitVec { - fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> ManuallyDrop { + fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> Result { let storage = match self.clone().into_storage() { InternalStorage::Spilled(vs) => { // Reserve space for the boxed slice values. @@ -524,13 +546,15 @@ impl ToShmem for SmallBitVec { }, InternalStorage::Inline(x) => InternalStorage::Inline(x), }; - ManuallyDrop::new(unsafe { SmallBitVec::from_storage(storage) }) + Ok(ManuallyDrop::new(unsafe { + SmallBitVec::from_storage(storage) + })) } } #[cfg(feature = "string_cache")] impl ToShmem for string_cache::Atom { - fn to_shmem(&self, _: &mut SharedMemoryBuilder) -> ManuallyDrop { + fn to_shmem(&self, _: &mut SharedMemoryBuilder) -> Result { // NOTE(emilio): In practice, this can be implemented trivially if // string_cache could expose the implementation detail of static atoms // being an index into the static table (and panicking in the diff --git a/components/to_shmem_derive/to_shmem.rs b/components/to_shmem_derive/to_shmem.rs index 01ba308e308..c3410bcc7e0 100644 --- a/components/to_shmem_derive/to_shmem.rs +++ b/components/to_shmem_derive/to_shmem.rs @@ -27,13 +27,23 @@ pub fn derive(mut input: syn::DeriveInput) -> TokenStream { input.generics.where_clause = where_clause; - let match_body = cg::fmap_match(&input, BindStyle::Ref, |binding| { - quote! { - ::std::mem::ManuallyDrop::into_inner( - ::to_shmem::ToShmem::to_shmem(#binding, builder) - ) - } - }); + // Do all of the `to_shmem()?` calls before the `ManuallyDrop::into_inner()` + // calls, so that we don't drop a value in the shared memory buffer if one + // of the `to_shmem`s fails. + let match_body = cg::fmap2_match( + &input, + BindStyle::Ref, + |binding| { + quote! { + ::to_shmem::ToShmem::to_shmem(#binding, builder)? + } + }, + |binding| { + Some(quote! { + ::std::mem::ManuallyDrop::into_inner(#binding) + }) + }, + ); let name = &input.ident; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); @@ -44,12 +54,12 @@ pub fn derive(mut input: syn::DeriveInput) -> TokenStream { fn to_shmem( &self, builder: &mut ::to_shmem::SharedMemoryBuilder, - ) -> ::std::mem::ManuallyDrop { - ::std::mem::ManuallyDrop::new( + ) -> ::to_shmem::Result { + Ok(::std::mem::ManuallyDrop::new( match *self { #match_body } - ) + )) } } }