]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_mir/src/interpret/validity.rs
use iter:: before free functions
[rust.git] / compiler / rustc_mir / src / interpret / validity.rs
1 //! Check the validity invariant of a given value, and tell the user
2 //! where in the value it got violated.
3 //! In const context, this goes even further and tries to approximate const safety.
4 //! That's useful because it means other passes (e.g. promotion) can rely on `const`s
5 //! to be const-safe.
6
7 use std::convert::TryFrom;
8 use std::fmt::Write;
9 use std::num::NonZeroUsize;
10 use std::ops::RangeInclusive;
11
12 use rustc_data_structures::fx::FxHashSet;
13 use rustc_hir as hir;
14 use rustc_middle::mir::interpret::{InterpError, InterpErrorInfo};
15 use rustc_middle::ty;
16 use rustc_middle::ty::layout::TyAndLayout;
17 use rustc_span::symbol::{sym, Symbol};
18 use rustc_target::abi::{Abi, LayoutOf, Scalar, Size, VariantIdx, Variants};
19
20 use std::hash::Hash;
21
22 use super::{
23     CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy,
24     ValueVisitor,
25 };
26
27 macro_rules! throw_validation_failure {
28     ($where:expr, { $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )?) => {{
29         let msg = rustc_middle::ty::print::with_no_trimmed_paths(|| {
30             let mut msg = String::new();
31             msg.push_str("encountered ");
32             write!(&mut msg, $($what_fmt),+).unwrap();
33             let where_ = &$where;
34             if !where_.is_empty() {
35                 msg.push_str(" at ");
36                 write_path(&mut msg, where_);
37             }
38             $(
39                 msg.push_str(", but expected ");
40                 write!(&mut msg, $($expected_fmt),+).unwrap();
41             )?
42
43             msg
44         });
45         throw_ub!(ValidationFailure(msg))
46     }};
47 }
48
49 /// If $e throws an error matching the pattern, throw a validation failure.
50 /// Other errors are passed back to the caller, unchanged -- and if they reach the root of
51 /// the visitor, we make sure only validation errors and `InvalidProgram` errors are left.
52 /// This lets you use the patterns as a kind of validation list, asserting which errors
53 /// can possibly happen:
54 ///
55 /// ```
56 /// let v = try_validation!(some_fn(), some_path, {
57 ///     Foo | Bar | Baz => { "some failure" },
58 /// });
59 /// ```
60 ///
61 /// An additional expected parameter can also be added to the failure message:
62 ///
63 /// ```
64 /// let v = try_validation!(some_fn(), some_path, {
65 ///     Foo | Bar | Baz => { "some failure" } expected { "something that wasn't a failure" },
66 /// });
67 /// ```
68 ///
69 /// An additional nicety is that both parameters actually take format args, so you can just write
70 /// the format string in directly:
71 ///
72 /// ```
73 /// let v = try_validation!(some_fn(), some_path, {
74 ///     Foo | Bar | Baz => { "{:?}", some_failure } expected { "{}", expected_value },
75 /// });
76 /// ```
77 ///
78 macro_rules! try_validation {
79     ($e:expr, $where:expr,
80      $( $( $p:pat )|+ => { $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )? ),+ $(,)?
81     ) => {{
82         match $e {
83             Ok(x) => x,
84             // We catch the error and turn it into a validation failure. We are okay with
85             // allocation here as this can only slow down builds that fail anyway.
86             $( $( Err(InterpErrorInfo { kind: $p, .. }) )|+ =>
87                 throw_validation_failure!(
88                     $where,
89                     { $( $what_fmt ),+ } $( expected { $( $expected_fmt ),+ } )?
90                 ),
91             )+
92             #[allow(unreachable_patterns)]
93             Err(e) => Err::<!, _>(e)?,
94         }
95     }};
96 }
97
98 /// We want to show a nice path to the invalid field for diagnostics,
99 /// but avoid string operations in the happy case where no error happens.
100 /// So we track a `Vec<PathElem>` where `PathElem` contains all the data we
101 /// need to later print something for the user.
102 #[derive(Copy, Clone, Debug)]
103 pub enum PathElem {
104     Field(Symbol),
105     Variant(Symbol),
106     GeneratorState(VariantIdx),
107     CapturedVar(Symbol),
108     ArrayElem(usize),
109     TupleElem(usize),
110     Deref,
111     EnumTag,
112     GeneratorTag,
113     DynDowncast,
114 }
115
116 /// State for tracking recursive validation of references
117 pub struct RefTracking<T, PATH = ()> {
118     pub seen: FxHashSet<T>,
119     pub todo: Vec<(T, PATH)>,
120 }
121
122 impl<T: Copy + Eq + Hash + std::fmt::Debug, PATH: Default> RefTracking<T, PATH> {
123     pub fn empty() -> Self {
124         RefTracking { seen: FxHashSet::default(), todo: vec![] }
125     }
126     pub fn new(op: T) -> Self {
127         let mut ref_tracking_for_consts =
128             RefTracking { seen: FxHashSet::default(), todo: vec![(op, PATH::default())] };
129         ref_tracking_for_consts.seen.insert(op);
130         ref_tracking_for_consts
131     }
132
133     pub fn track(&mut self, op: T, path: impl FnOnce() -> PATH) {
134         if self.seen.insert(op) {
135             trace!("Recursing below ptr {:#?}", op);
136             let path = path();
137             // Remember to come back to this later.
138             self.todo.push((op, path));
139         }
140     }
141 }
142
143 /// Format a path
144 fn write_path(out: &mut String, path: &Vec<PathElem>) {
145     use self::PathElem::*;
146
147     for elem in path.iter() {
148         match elem {
149             Field(name) => write!(out, ".{}", name),
150             EnumTag => write!(out, ".<enum-tag>"),
151             Variant(name) => write!(out, ".<enum-variant({})>", name),
152             GeneratorTag => write!(out, ".<generator-tag>"),
153             GeneratorState(idx) => write!(out, ".<generator-state({})>", idx.index()),
154             CapturedVar(name) => write!(out, ".<captured-var({})>", name),
155             TupleElem(idx) => write!(out, ".{}", idx),
156             ArrayElem(idx) => write!(out, "[{}]", idx),
157             // `.<deref>` does not match Rust syntax, but it is more readable for long paths -- and
158             // some of the other items here also are not Rust syntax.  Actually we can't
159             // even use the usual syntax because we are just showing the projections,
160             // not the root.
161             Deref => write!(out, ".<deref>"),
162             DynDowncast => write!(out, ".<dyn-downcast>"),
163         }
164         .unwrap()
165     }
166 }
167
168 // Test if a range that wraps at overflow contains `test`
169 fn wrapping_range_contains(r: &RangeInclusive<u128>, test: u128) -> bool {
170     let (lo, hi) = r.clone().into_inner();
171     if lo > hi {
172         // Wrapped
173         (..=hi).contains(&test) || (lo..).contains(&test)
174     } else {
175         // Normal
176         r.contains(&test)
177     }
178 }
179
180 // Formats such that a sentence like "expected something {}" to mean
181 // "expected something <in the given range>" makes sense.
182 fn wrapping_range_format(r: &RangeInclusive<u128>, max_hi: u128) -> String {
183     let (lo, hi) = r.clone().into_inner();
184     assert!(hi <= max_hi);
185     if lo > hi {
186         format!("less or equal to {}, or greater or equal to {}", hi, lo)
187     } else if lo == hi {
188         format!("equal to {}", lo)
189     } else if lo == 0 {
190         assert!(hi < max_hi, "should not be printing if the range covers everything");
191         format!("less or equal to {}", hi)
192     } else if hi == max_hi {
193         assert!(lo > 0, "should not be printing if the range covers everything");
194         format!("greater or equal to {}", lo)
195     } else {
196         format!("in the range {:?}", r)
197     }
198 }
199
200 struct ValidityVisitor<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> {
201     /// The `path` may be pushed to, but the part that is present when a function
202     /// starts must not be changed!  `visit_fields` and `visit_array` rely on
203     /// this stack discipline.
204     path: Vec<PathElem>,
205     ref_tracking_for_consts:
206         Option<&'rt mut RefTracking<MPlaceTy<'tcx, M::PointerTag>, Vec<PathElem>>>,
207     may_ref_to_static: bool,
208     ecx: &'rt InterpCx<'mir, 'tcx, M>,
209 }
210
211 impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M> {
212     fn aggregate_field_path_elem(&mut self, layout: TyAndLayout<'tcx>, field: usize) -> PathElem {
213         // First, check if we are projecting to a variant.
214         match layout.variants {
215             Variants::Multiple { tag_field, .. } => {
216                 if tag_field == field {
217                     return match layout.ty.kind() {
218                         ty::Adt(def, ..) if def.is_enum() => PathElem::EnumTag,
219                         ty::Generator(..) => PathElem::GeneratorTag,
220                         _ => bug!("non-variant type {:?}", layout.ty),
221                     };
222                 }
223             }
224             Variants::Single { .. } => {}
225         }
226
227         // Now we know we are projecting to a field, so figure out which one.
228         match layout.ty.kind() {
229             // generators and closures.
230             ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
231                 let mut name = None;
232                 if let Some(def_id) = def_id.as_local() {
233                     let tables = self.ecx.tcx.typeck(def_id);
234                     if let Some(upvars) = tables.closure_captures.get(&def_id.to_def_id()) {
235                         // Sometimes the index is beyond the number of upvars (seen
236                         // for a generator).
237                         if let Some((&var_hir_id, _)) = upvars.get_index(field) {
238                             let node = self.ecx.tcx.hir().get(var_hir_id);
239                             if let hir::Node::Binding(pat) = node {
240                                 if let hir::PatKind::Binding(_, _, ident, _) = pat.kind {
241                                     name = Some(ident.name);
242                                 }
243                             }
244                         }
245                     }
246                 }
247
248                 PathElem::CapturedVar(name.unwrap_or_else(|| {
249                     // Fall back to showing the field index.
250                     sym::integer(field)
251                 }))
252             }
253
254             // tuples
255             ty::Tuple(_) => PathElem::TupleElem(field),
256
257             // enums
258             ty::Adt(def, ..) if def.is_enum() => {
259                 // we might be projecting *to* a variant, or to a field *in* a variant.
260                 match layout.variants {
261                     Variants::Single { index } => {
262                         // Inside a variant
263                         PathElem::Field(def.variants[index].fields[field].ident.name)
264                     }
265                     Variants::Multiple { .. } => bug!("we handled variants above"),
266                 }
267             }
268
269             // other ADTs
270             ty::Adt(def, _) => PathElem::Field(def.non_enum_variant().fields[field].ident.name),
271
272             // arrays/slices
273             ty::Array(..) | ty::Slice(..) => PathElem::ArrayElem(field),
274
275             // dyn traits
276             ty::Dynamic(..) => PathElem::DynDowncast,
277
278             // nothing else has an aggregate layout
279             _ => bug!("aggregate_field_path_elem: got non-aggregate type {:?}", layout.ty),
280         }
281     }
282
283     fn with_elem<R>(
284         &mut self,
285         elem: PathElem,
286         f: impl FnOnce(&mut Self) -> InterpResult<'tcx, R>,
287     ) -> InterpResult<'tcx, R> {
288         // Remember the old state
289         let path_len = self.path.len();
290         // Record new element
291         self.path.push(elem);
292         // Perform operation
293         let r = f(self)?;
294         // Undo changes
295         self.path.truncate(path_len);
296         // Done
297         Ok(r)
298     }
299
300     fn check_wide_ptr_meta(
301         &mut self,
302         meta: MemPlaceMeta<M::PointerTag>,
303         pointee: TyAndLayout<'tcx>,
304     ) -> InterpResult<'tcx> {
305         let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env);
306         match tail.kind() {
307             ty::Dynamic(..) => {
308                 let vtable = meta.unwrap_meta();
309                 // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines.
310                 try_validation!(
311                     self.ecx.memory.check_ptr_access_align(
312                         vtable,
313                         3 * self.ecx.tcx.data_layout.pointer_size, // drop, size, align
314                         Some(self.ecx.tcx.data_layout.pointer_align.abi),
315                         CheckInAllocMsg::InboundsTest,
316                     ),
317                     self.path,
318                     err_ub!(DanglingIntPointer(..)) |
319                     err_ub!(PointerUseAfterFree(..)) |
320                     err_unsup!(ReadBytesAsPointer) =>
321                         { "dangling vtable pointer in wide pointer" },
322                     err_ub!(AlignmentCheckFailed { .. }) =>
323                         { "unaligned vtable pointer in wide pointer" },
324                     err_ub!(PointerOutOfBounds { .. }) =>
325                         { "too small vtable" },
326                 );
327                 try_validation!(
328                     self.ecx.read_drop_type_from_vtable(vtable),
329                     self.path,
330                     err_ub!(DanglingIntPointer(..)) |
331                     err_ub!(InvalidFunctionPointer(..)) |
332                     err_unsup!(ReadBytesAsPointer) =>
333                         { "invalid drop function pointer in vtable (not pointing to a function)" },
334                     err_ub!(InvalidDropFn(..)) =>
335                         { "invalid drop function pointer in vtable (function has incompatible signature)" },
336                 );
337                 try_validation!(
338                     self.ecx.read_size_and_align_from_vtable(vtable),
339                     self.path,
340                     err_unsup!(ReadPointerAsBytes) => { "invalid size or align in vtable" },
341                 );
342                 // FIXME: More checks for the vtable.
343             }
344             ty::Slice(..) | ty::Str => {
345                 let _len = try_validation!(
346                     meta.unwrap_meta().to_machine_usize(self.ecx),
347                     self.path,
348                     err_unsup!(ReadPointerAsBytes) => { "non-integer slice length in wide pointer" },
349                 );
350                 // We do not check that `len * elem_size <= isize::MAX`:
351                 // that is only required for references, and there it falls out of the
352                 // "dereferenceable" check performed by Stacked Borrows.
353             }
354             ty::Foreign(..) => {
355                 // Unsized, but not wide.
356             }
357             _ => bug!("Unexpected unsized type tail: {:?}", tail),
358         }
359
360         Ok(())
361     }
362
363     /// Check a reference or `Box`.
364     fn check_safe_pointer(
365         &mut self,
366         value: OpTy<'tcx, M::PointerTag>,
367         kind: &str,
368     ) -> InterpResult<'tcx> {
369         let value = self.ecx.read_immediate(value)?;
370         // Handle wide pointers.
371         // Check metadata early, for better diagnostics
372         let place = try_validation!(
373             self.ecx.ref_to_mplace(value),
374             self.path,
375             err_ub!(InvalidUninitBytes(None)) => { "uninitialized {}", kind },
376         );
377         if place.layout.is_unsized() {
378             self.check_wide_ptr_meta(place.meta, place.layout)?;
379         }
380         // Make sure this is dereferenceable and all.
381         let size_and_align = try_validation!(
382             self.ecx.size_and_align_of(place.meta, place.layout),
383             self.path,
384             err_ub!(InvalidMeta(msg)) => { "invalid {} metadata: {}", kind, msg },
385         );
386         let (size, align) = size_and_align
387             // for the purpose of validity, consider foreign types to have
388             // alignment and size determined by the layout (size will be 0,
389             // alignment should take attributes into account).
390             .unwrap_or_else(|| (place.layout.size, place.layout.align.abi));
391         // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines.
392         let ptr: Option<_> = try_validation!(
393             self.ecx.memory.check_ptr_access_align(
394                 place.ptr,
395                 size,
396                 Some(align),
397                 CheckInAllocMsg::InboundsTest,
398             ),
399             self.path,
400             err_ub!(AlignmentCheckFailed { required, has }) =>
401                 {
402                     "an unaligned {} (required {} byte alignment but found {})",
403                     kind,
404                     required.bytes(),
405                     has.bytes()
406                 },
407             err_ub!(DanglingIntPointer(0, _)) =>
408                 { "a NULL {}", kind },
409             err_ub!(DanglingIntPointer(i, _)) =>
410                 { "a dangling {} (address 0x{:x} is unallocated)", kind, i },
411             err_ub!(PointerOutOfBounds { .. }) =>
412                 { "a dangling {} (going beyond the bounds of its allocation)", kind },
413             err_unsup!(ReadBytesAsPointer) =>
414                 { "a dangling {} (created from integer)", kind },
415             // This cannot happen during const-eval (because interning already detects
416             // dangling pointers), but it can happen in Miri.
417             err_ub!(PointerUseAfterFree(..)) =>
418                 { "a dangling {} (use-after-free)", kind },
419         );
420         // Recursive checking
421         if let Some(ref mut ref_tracking) = self.ref_tracking_for_consts {
422             if let Some(ptr) = ptr {
423                 // not a ZST
424                 // Skip validation entirely for some external statics
425                 let alloc_kind = self.ecx.tcx.get_global_alloc(ptr.alloc_id);
426                 if let Some(GlobalAlloc::Static(did)) = alloc_kind {
427                     assert!(!self.ecx.tcx.is_thread_local_static(did));
428                     // See const_eval::machine::MemoryExtra::can_access_statics for why
429                     // this check is so important.
430                     // This check is reachable when the const just referenced the static,
431                     // but never read it (so we never entered `before_access_global`).
432                     // We also need to do it here instead of going on to avoid running
433                     // into the `before_access_global` check during validation.
434                     if !self.may_ref_to_static && self.ecx.tcx.is_static(did) {
435                         throw_validation_failure!(self.path,
436                             { "a {} pointing to a static variable", kind }
437                         );
438                     }
439                     // `extern static` cannot be validated as they have no body.
440                     // FIXME: Statics from other crates are also skipped.
441                     // They might be checked at a different type, but for now we
442                     // want to avoid recursing too deeply.  We might miss const-invalid data,
443                     // but things are still sound otherwise (in particular re: consts
444                     // referring to statics).
445                     if !did.is_local() || self.ecx.tcx.is_foreign_item(did) {
446                         return Ok(());
447                     }
448                 }
449             }
450             // Proceed recursively even for ZST, no reason to skip them!
451             // `!` is a ZST and we want to validate it.
452             // Normalize before handing `place` to tracking because that will
453             // check for duplicates.
454             let place = if size.bytes() > 0 {
455                 self.ecx.force_mplace_ptr(place).expect("we already bounds-checked")
456             } else {
457                 place
458             };
459             let path = &self.path;
460             ref_tracking.track(place, || {
461                 // We need to clone the path anyway, make sure it gets created
462                 // with enough space for the additional `Deref`.
463                 let mut new_path = Vec::with_capacity(path.len() + 1);
464                 new_path.clone_from(path);
465                 new_path.push(PathElem::Deref);
466                 new_path
467             });
468         }
469         Ok(())
470     }
471
472     /// Check if this is a value of primitive type, and if yes check the validity of the value
473     /// at that type.  Return `true` if the type is indeed primitive.
474     fn try_visit_primitive(
475         &mut self,
476         value: OpTy<'tcx, M::PointerTag>,
477     ) -> InterpResult<'tcx, bool> {
478         // Go over all the primitive types
479         let ty = value.layout.ty;
480         match ty.kind() {
481             ty::Bool => {
482                 let value = self.ecx.read_scalar(value)?;
483                 try_validation!(
484                     value.to_bool(),
485                     self.path,
486                     err_ub!(InvalidBool(..)) | err_ub!(InvalidUninitBytes(None)) =>
487                         { "{}", value } expected { "a boolean" },
488                 );
489                 Ok(true)
490             }
491             ty::Char => {
492                 let value = self.ecx.read_scalar(value)?;
493                 try_validation!(
494                     value.to_char(),
495                     self.path,
496                     err_ub!(InvalidChar(..)) | err_ub!(InvalidUninitBytes(None)) =>
497                         { "{}", value } expected { "a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)" },
498                 );
499                 Ok(true)
500             }
501             ty::Float(_) | ty::Int(_) | ty::Uint(_) => {
502                 let value = self.ecx.read_scalar(value)?;
503                 // NOTE: Keep this in sync with the array optimization for int/float
504                 // types below!
505                 if self.ref_tracking_for_consts.is_some() {
506                     // Integers/floats in CTFE: Must be scalar bits, pointers are dangerous
507                     let is_bits = value.check_init().map_or(false, |v| v.is_bits());
508                     if !is_bits {
509                         throw_validation_failure!(self.path,
510                             { "{}", value } expected { "initialized plain (non-pointer) bytes" }
511                         )
512                     }
513                 } else {
514                     // At run-time, for now, we accept *anything* for these types, including
515                     // uninit. We should fix that, but let's start low.
516                 }
517                 Ok(true)
518             }
519             ty::RawPtr(..) => {
520                 // We are conservative with uninit for integers, but try to
521                 // actually enforce the strict rules for raw pointers (mostly because
522                 // that lets us re-use `ref_to_mplace`).
523                 let place = try_validation!(
524                     self.ecx.ref_to_mplace(self.ecx.read_immediate(value)?),
525                     self.path,
526                     err_ub!(InvalidUninitBytes(None)) => { "uninitialized raw pointer" },
527                 );
528                 if place.layout.is_unsized() {
529                     self.check_wide_ptr_meta(place.meta, place.layout)?;
530                 }
531                 Ok(true)
532             }
533             ty::Ref(..) => {
534                 self.check_safe_pointer(value, "reference")?;
535                 Ok(true)
536             }
537             ty::Adt(def, ..) if def.is_box() => {
538                 self.check_safe_pointer(value, "box")?;
539                 Ok(true)
540             }
541             ty::FnPtr(_sig) => {
542                 let value = self.ecx.read_scalar(value)?;
543                 let _fn = try_validation!(
544                     value.check_init().and_then(|ptr| self.ecx.memory.get_fn(ptr)),
545                     self.path,
546                     err_ub!(DanglingIntPointer(..)) |
547                     err_ub!(InvalidFunctionPointer(..)) |
548                     err_ub!(InvalidUninitBytes(None)) |
549                     err_unsup!(ReadBytesAsPointer) =>
550                         { "{}", value } expected { "a function pointer" },
551                 );
552                 // FIXME: Check if the signature matches
553                 Ok(true)
554             }
555             ty::Never => throw_validation_failure!(self.path, { "a value of the never type `!`" }),
556             ty::Foreign(..) | ty::FnDef(..) => {
557                 // Nothing to check.
558                 Ok(true)
559             }
560             // The above should be all the (inhabited) primitive types. The rest is compound, we
561             // check them by visiting their fields/variants.
562             // (`Str` UTF-8 check happens in `visit_aggregate`, too.)
563             ty::Adt(..)
564             | ty::Tuple(..)
565             | ty::Array(..)
566             | ty::Slice(..)
567             | ty::Str
568             | ty::Dynamic(..)
569             | ty::Closure(..)
570             | ty::Generator(..) => Ok(false),
571             // Some types only occur during typechecking, they have no layout.
572             // We should not see them here and we could not check them anyway.
573             ty::Error(_)
574             | ty::Infer(..)
575             | ty::Placeholder(..)
576             | ty::Bound(..)
577             | ty::Param(..)
578             | ty::Opaque(..)
579             | ty::Projection(..)
580             | ty::GeneratorWitness(..) => bug!("Encountered invalid type {:?}", ty),
581         }
582     }
583
584     fn visit_scalar(
585         &mut self,
586         op: OpTy<'tcx, M::PointerTag>,
587         scalar_layout: &Scalar,
588     ) -> InterpResult<'tcx> {
589         let value = self.ecx.read_scalar(op)?;
590         let valid_range = &scalar_layout.valid_range;
591         let (lo, hi) = valid_range.clone().into_inner();
592         // Determine the allowed range
593         // `max_hi` is as big as the size fits
594         let max_hi = u128::MAX >> (128 - op.layout.size.bits());
595         assert!(hi <= max_hi);
596         // We could also write `(hi + 1) % (max_hi + 1) == lo` but `max_hi + 1` overflows for `u128`
597         if (lo == 0 && hi == max_hi) || (hi + 1 == lo) {
598             // Nothing to check
599             return Ok(());
600         }
601         // At least one value is excluded. Get the bits.
602         let value = try_validation!(
603             value.check_init(),
604             self.path,
605             err_ub!(InvalidUninitBytes(None)) => { "{}", value }
606                 expected { "something {}", wrapping_range_format(valid_range, max_hi) },
607         );
608         let bits = match value.to_bits_or_ptr(op.layout.size, self.ecx) {
609             Err(ptr) => {
610                 if lo == 1 && hi == max_hi {
611                     // Only NULL is the niche.  So make sure the ptr is NOT NULL.
612                     if self.ecx.memory.ptr_may_be_null(ptr) {
613                         throw_validation_failure!(self.path,
614                             { "a potentially NULL pointer" }
615                             expected {
616                                 "something that cannot possibly fail to be {}",
617                                 wrapping_range_format(valid_range, max_hi)
618                             }
619                         )
620                     }
621                     return Ok(());
622                 } else {
623                     // Conservatively, we reject, because the pointer *could* have a bad
624                     // value.
625                     throw_validation_failure!(self.path,
626                         { "a pointer" }
627                         expected {
628                             "something that cannot possibly fail to be {}",
629                             wrapping_range_format(valid_range, max_hi)
630                         }
631                     )
632                 }
633             }
634             Ok(data) => data,
635         };
636         // Now compare. This is slightly subtle because this is a special "wrap-around" range.
637         if wrapping_range_contains(&valid_range, bits) {
638             Ok(())
639         } else {
640             throw_validation_failure!(self.path,
641                 { "{}", bits }
642                 expected { "something {}", wrapping_range_format(valid_range, max_hi) }
643             )
644         }
645     }
646 }
647
648 impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
649     for ValidityVisitor<'rt, 'mir, 'tcx, M>
650 {
651     type V = OpTy<'tcx, M::PointerTag>;
652
653     #[inline(always)]
654     fn ecx(&self) -> &InterpCx<'mir, 'tcx, M> {
655         &self.ecx
656     }
657
658     fn read_discriminant(
659         &mut self,
660         op: OpTy<'tcx, M::PointerTag>,
661     ) -> InterpResult<'tcx, VariantIdx> {
662         self.with_elem(PathElem::EnumTag, move |this| {
663             Ok(try_validation!(
664                 this.ecx.read_discriminant(op),
665                 this.path,
666                 err_ub!(InvalidTag(val)) =>
667                     { "{}", val } expected { "a valid enum tag" },
668                 err_ub!(InvalidUninitBytes(None)) =>
669                     { "uninitialized bytes" } expected { "a valid enum tag" },
670                 err_unsup!(ReadPointerAsBytes) =>
671                     { "a pointer" } expected { "a valid enum tag" },
672             )
673             .1)
674         })
675     }
676
677     #[inline]
678     fn visit_field(
679         &mut self,
680         old_op: OpTy<'tcx, M::PointerTag>,
681         field: usize,
682         new_op: OpTy<'tcx, M::PointerTag>,
683     ) -> InterpResult<'tcx> {
684         let elem = self.aggregate_field_path_elem(old_op.layout, field);
685         self.with_elem(elem, move |this| this.visit_value(new_op))
686     }
687
688     #[inline]
689     fn visit_variant(
690         &mut self,
691         old_op: OpTy<'tcx, M::PointerTag>,
692         variant_id: VariantIdx,
693         new_op: OpTy<'tcx, M::PointerTag>,
694     ) -> InterpResult<'tcx> {
695         let name = match old_op.layout.ty.kind() {
696             ty::Adt(adt, _) => PathElem::Variant(adt.variants[variant_id].ident.name),
697             // Generators also have variants
698             ty::Generator(..) => PathElem::GeneratorState(variant_id),
699             _ => bug!("Unexpected type with variant: {:?}", old_op.layout.ty),
700         };
701         self.with_elem(name, move |this| this.visit_value(new_op))
702     }
703
704     #[inline(always)]
705     fn visit_union(
706         &mut self,
707         _op: OpTy<'tcx, M::PointerTag>,
708         _fields: NonZeroUsize,
709     ) -> InterpResult<'tcx> {
710         Ok(())
711     }
712
713     #[inline]
714     fn visit_value(&mut self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
715         trace!("visit_value: {:?}, {:?}", *op, op.layout);
716
717         // Check primitive types -- the leafs of our recursive descend.
718         if self.try_visit_primitive(op)? {
719             return Ok(());
720         }
721         // Sanity check: `builtin_deref` does not know any pointers that are not primitive.
722         assert!(op.layout.ty.builtin_deref(true).is_none());
723
724         // Recursively walk the value at its type.
725         self.walk_value(op)?;
726
727         // *After* all of this, check the ABI.  We need to check the ABI to handle
728         // types like `NonNull` where the `Scalar` info is more restrictive than what
729         // the fields say (`rustc_layout_scalar_valid_range_start`).
730         // But in most cases, this will just propagate what the fields say,
731         // and then we want the error to point at the field -- so, first recurse,
732         // then check ABI.
733         //
734         // FIXME: We could avoid some redundant checks here. For newtypes wrapping
735         // scalars, we do the same check on every "level" (e.g., first we check
736         // MyNewtype and then the scalar in there).
737         match op.layout.abi {
738             Abi::Uninhabited => {
739                 throw_validation_failure!(self.path,
740                     { "a value of uninhabited type {:?}", op.layout.ty }
741                 );
742             }
743             Abi::Scalar(ref scalar_layout) => {
744                 self.visit_scalar(op, scalar_layout)?;
745             }
746             Abi::ScalarPair { .. } | Abi::Vector { .. } => {
747                 // These have fields that we already visited above, so we already checked
748                 // all their scalar-level restrictions.
749                 // There is also no equivalent to `rustc_layout_scalar_valid_range_start`
750                 // that would make skipping them here an issue.
751             }
752             Abi::Aggregate { .. } => {
753                 // Nothing to do.
754             }
755         }
756
757         Ok(())
758     }
759
760     fn visit_aggregate(
761         &mut self,
762         op: OpTy<'tcx, M::PointerTag>,
763         fields: impl Iterator<Item = InterpResult<'tcx, Self::V>>,
764     ) -> InterpResult<'tcx> {
765         match op.layout.ty.kind() {
766             ty::Str => {
767                 let mplace = op.assert_mem_place(self.ecx); // strings are never immediate
768                 let len = mplace.len(self.ecx)?;
769                 try_validation!(
770                     self.ecx.memory.read_bytes(mplace.ptr, Size::from_bytes(len)),
771                     self.path,
772                     err_ub!(InvalidUninitBytes(..)) => { "uninitialized data in `str`" },
773                 );
774             }
775             ty::Array(tys, ..) | ty::Slice(tys)
776                 if {
777                     // This optimization applies for types that can hold arbitrary bytes (such as
778                     // integer and floating point types) or for structs or tuples with no fields.
779                     // FIXME(wesleywiser) This logic could be extended further to arbitrary structs
780                     // or tuples made up of integer/floating point types or inhabited ZSTs with no
781                     // padding.
782                     match tys.kind() {
783                         ty::Int(..) | ty::Uint(..) | ty::Float(..) => true,
784                         _ => false,
785                     }
786                 } =>
787             {
788                 // Optimized handling for arrays of integer/float type.
789
790                 // Arrays cannot be immediate, slices are never immediate.
791                 let mplace = op.assert_mem_place(self.ecx);
792                 // This is the length of the array/slice.
793                 let len = mplace.len(self.ecx)?;
794                 // Zero length slices have nothing to be checked.
795                 if len == 0 {
796                     return Ok(());
797                 }
798                 // This is the element type size.
799                 let layout = self.ecx.layout_of(tys)?;
800                 // This is the size in bytes of the whole array. (This checks for overflow.)
801                 let size = layout.size * len;
802                 // Size is not 0, get a pointer.
803                 let ptr = self.ecx.force_ptr(mplace.ptr)?;
804
805                 // Optimization: we just check the entire range at once.
806                 // NOTE: Keep this in sync with the handling of integer and float
807                 // types above, in `visit_primitive`.
808                 // In run-time mode, we accept pointers in here.  This is actually more
809                 // permissive than a per-element check would be, e.g., we accept
810                 // an &[u8] that contains a pointer even though bytewise checking would
811                 // reject it.  However, that's good: We don't inherently want
812                 // to reject those pointers, we just do not have the machinery to
813                 // talk about parts of a pointer.
814                 // We also accept uninit, for consistency with the slow path.
815                 match self.ecx.memory.get_raw(ptr.alloc_id)?.check_bytes(
816                     self.ecx,
817                     ptr,
818                     size,
819                     /*allow_uninit_and_ptr*/ self.ref_tracking_for_consts.is_none(),
820                 ) {
821                     // In the happy case, we needn't check anything else.
822                     Ok(()) => {}
823                     // Some error happened, try to provide a more detailed description.
824                     Err(err) => {
825                         // For some errors we might be able to provide extra information.
826                         // (This custom logic does not fit the `try_validation!` macro.)
827                         match err.kind {
828                             err_ub!(InvalidUninitBytes(Some(access))) => {
829                                 // Some byte was uninitialized, determine which
830                                 // element that byte belongs to so we can
831                                 // provide an index.
832                                 let i = usize::try_from(
833                                     access.uninit_ptr.offset.bytes() / layout.size.bytes(),
834                                 )
835                                 .unwrap();
836                                 self.path.push(PathElem::ArrayElem(i));
837
838                                 throw_validation_failure!(self.path, { "uninitialized bytes" })
839                             }
840                             err_unsup!(ReadPointerAsBytes) => {
841                                 throw_validation_failure!(self.path, { "a pointer" } expected { "plain (non-pointer) bytes" })
842                             }
843
844                             // Propagate upwards (that will also check for unexpected errors).
845                             _ => return Err(err),
846                         }
847                     }
848                 }
849             }
850             // Fast path for arrays and slices of ZSTs. We only need to check a single ZST element
851             // of an array and not all of them, because there's only a single value of a specific
852             // ZST type, so either validation fails for all elements or none.
853             ty::Array(tys, ..) | ty::Slice(tys) if self.ecx.layout_of(tys)?.is_zst() => {
854                 // Validate just the first element
855                 self.walk_aggregate(op, fields.take(1))?
856             }
857             _ => {
858                 self.walk_aggregate(op, fields)? // default handler
859             }
860         }
861         Ok(())
862     }
863 }
864
865 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
866     fn validate_operand_internal(
867         &self,
868         op: OpTy<'tcx, M::PointerTag>,
869         path: Vec<PathElem>,
870         ref_tracking_for_consts: Option<
871             &mut RefTracking<MPlaceTy<'tcx, M::PointerTag>, Vec<PathElem>>,
872         >,
873         may_ref_to_static: bool,
874     ) -> InterpResult<'tcx> {
875         trace!("validate_operand_internal: {:?}, {:?}", *op, op.layout.ty);
876
877         // Construct a visitor
878         let mut visitor =
879             ValidityVisitor { path, ref_tracking_for_consts, may_ref_to_static, ecx: self };
880
881         // Try to cast to ptr *once* instead of all the time.
882         let op = self.force_op_ptr(op).unwrap_or(op);
883
884         // Run it.
885         match visitor.visit_value(op) {
886             Ok(()) => Ok(()),
887             // Pass through validation failures.
888             Err(err) if matches!(err.kind, err_ub!(ValidationFailure { .. })) => Err(err),
889             // Also pass through InvalidProgram, those just indicate that we could not
890             // validate and each caller will know best what to do with them.
891             Err(err) if matches!(err.kind, InterpError::InvalidProgram(_)) => Err(err),
892             // Avoid other errors as those do not show *where* in the value the issue lies.
893             Err(err) => {
894                 err.print_backtrace();
895                 bug!("Unexpected error during validation: {}", err);
896             }
897         }
898     }
899
900     /// This function checks the data at `op` to be const-valid.
901     /// `op` is assumed to cover valid memory if it is an indirect operand.
902     /// It will error if the bits at the destination do not match the ones described by the layout.
903     ///
904     /// `ref_tracking` is used to record references that we encounter so that they
905     /// can be checked recursively by an outside driving loop.
906     ///
907     /// `may_ref_to_static` controls whether references are allowed to point to statics.
908     #[inline(always)]
909     pub fn const_validate_operand(
910         &self,
911         op: OpTy<'tcx, M::PointerTag>,
912         path: Vec<PathElem>,
913         ref_tracking: &mut RefTracking<MPlaceTy<'tcx, M::PointerTag>, Vec<PathElem>>,
914         may_ref_to_static: bool,
915     ) -> InterpResult<'tcx> {
916         self.validate_operand_internal(op, path, Some(ref_tracking), may_ref_to_static)
917     }
918
919     /// This function checks the data at `op` to be runtime-valid.
920     /// `op` is assumed to cover valid memory if it is an indirect operand.
921     /// It will error if the bits at the destination do not match the ones described by the layout.
922     #[inline(always)]
923     pub fn validate_operand(&self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
924         self.validate_operand_internal(op, vec![], None, false)
925     }
926 }