]> git.lizzy.rs Git - rust.git/commitdiff
size_and_align_of can return no result for extern types
authorRalf Jung <post@ralfj.de>
Tue, 9 Oct 2018 20:41:41 +0000 (22:41 +0200)
committerRalf Jung <post@ralfj.de>
Sat, 13 Oct 2018 07:09:03 +0000 (09:09 +0200)
src/librustc_mir/interpret/eval_context.rs
src/librustc_mir/interpret/place.rs
src/librustc_mir/interpret/validity.rs

index b0b8962b76ab129e482a803d6ae62b57337744f4..bc613358152be2e46a5e4ecf416a79af4f0bbe44 100644 (file)
@@ -332,22 +332,16 @@ pub fn layout_of_local(
     }
 
     /// Return the actual dynamic size and alignment of the place at the given type.
-    /// Only the `meta` part of the place matters.
+    /// Only the "meta" (metadata) part of the place matters.
+    /// This can fail to provide an answer for extern types.
     pub(super) fn size_and_align_of(
         &self,
         metadata: Option<Scalar<M::PointerTag>>,
         layout: TyLayout<'tcx>,
-    ) -> EvalResult<'tcx, (Size, Align)> {
-        let metadata = match metadata {
-            None => {
-                assert!(!layout.is_unsized());
-                return Ok(layout.size_and_align())
-            }
-            Some(metadata) => {
-                assert!(layout.is_unsized());
-                metadata
-            }
-        };
+    ) -> EvalResult<'tcx, Option<(Size, Align)>> {
+        if !layout.is_unsized() {
+            return Ok(Some(layout.size_and_align()));
+        }
         match layout.ty.sty {
             ty::Adt(..) | ty::Tuple(..) => {
                 // First get the size of all statically known fields.
@@ -367,9 +361,11 @@ pub(super) fn size_and_align_of(
                 );
 
                 // Recurse to get the size of the dynamically sized field (must be
-                // the last field).
+                // the last field).  Can't have foreign types here, how would we
+                // adjust alignment and size for them?
                 let field = layout.field(self, layout.fields.count() - 1)?;
-                let (unsized_size, unsized_align) = self.size_and_align_of(Some(metadata), field)?;
+                let (unsized_size, unsized_align) = self.size_and_align_of(metadata, field)?
+                    .expect("Fields cannot be extern types");
 
                 // FIXME (#26403, #27023): We should be adding padding
                 // to `sized_size` (to accommodate the `unsized_align`
@@ -396,18 +392,22 @@ pub(super) fn size_and_align_of(
                 //
                 //   `(size + (align-1)) & -align`
 
-                Ok((size.abi_align(align), align))
+                Ok(Some((size.abi_align(align), align)))
             }
             ty::Dynamic(..) => {
-                let vtable = metadata.to_ptr()?;
+                let vtable = metadata.expect("dyn trait fat ptr must have vtable").to_ptr()?;
                 // the second entry in the vtable is the dynamic size of the object.
-                self.read_size_and_align_from_vtable(vtable)
+                Ok(Some(self.read_size_and_align_from_vtable(vtable)?))
             }
 
             ty::Slice(_) | ty::Str => {
-                let len = metadata.to_usize(self)?;
+                let len = metadata.expect("slice fat ptr must have vtable").to_usize(self)?;
                 let (elem_size, align) = layout.field(self, 0)?.size_and_align();
-                Ok((elem_size * len, align))
+                Ok(Some((elem_size * len, align)))
+            }
+
+            ty::Foreign(_) => {
+                Ok(None)
             }
 
             _ => bug!("size_and_align_of::<{:?}> not supported", layout.ty),
@@ -417,7 +417,7 @@ pub(super) fn size_and_align_of(
     pub fn size_and_align_of_mplace(
         &self,
         mplace: MPlaceTy<'tcx, M::PointerTag>
-    ) -> EvalResult<'tcx, (Size, Align)> {
+    ) -> EvalResult<'tcx, Option<(Size, Align)>> {
         self.size_and_align_of(mplace.meta, mplace.layout)
     }
 
index 55077c8b6f9dd89e0f5b9278ef1bafcaea6298f9..923f0dc4c291a8d305e3d215330d8892c45333cd 100644 (file)
@@ -319,9 +319,9 @@ pub fn mplace_field(
         // Offset may need adjustment for unsized fields
         let (meta, offset) = if field_layout.is_unsized() {
             // re-use parent metadata to determine dynamic field layout
-            let (_, align) = self.size_and_align_of(base.meta, field_layout)?;
+            let (_, align) = self.size_and_align_of(base.meta, field_layout)?
+                .expect("Fields cannot be extern types");
             (base.meta, offset.abi_align(align))
-
         } else {
             // base.meta could be present; we might be accessing a sized field of an unsized
             // struct.
index cff4a0a323e0bc9d3266cf2b896ae544be74a3f4..0c1dc092ce1479a830db749c5de3f38c8398e5bc 100644 (file)
@@ -208,7 +208,10 @@ fn validate_primitive_type(
                 // for safe ptrs, also check the ptr values itself
                 if !ty.is_unsafe_ptr() {
                     // Make sure this is non-NULL and aligned
-                    let (size, align) = self.size_and_align_of(place.meta, place.layout)?;
+                    let (size, align) = self.size_and_align_of(place.meta, place.layout)?
+                        // for the purpose of validity, consider foreign types to have
+                        // alignment 1 and size 0.
+                        .unwrap_or_else(|| (Size::ZERO, Align::from_bytes(1, 1).unwrap()));
                     match self.memory.check_align(place.ptr, align) {
                         Ok(_) => {},
                         Err(err) => match err.kind {