/// Check if this is a value of primitive type, and if yes check the validity of the value
/// at that type.  Return `true` if the type is indeed primitive.
Check if this is a value of primitive type, and if yes check the validity of the value
at that type.  Return `true` if the type is indeed primitive.
Check if this is a value of primitive type and if yes check the validity of the value at that type . Return ` true ` if the type is indeed primitive .
fn try_visit_primitive(
        &mut self,
        value: &OpTy<'tcx, M::PointerTag>,
    ) -> InterpResult<'tcx, bool> {
        // Go over all the primitive types
        let ty = value.layout.ty;
        match ty.kind() {
            ty::Bool => {
                let value = self.read_scalar(value)?;
                try_validation!(
                    value.to_bool(),
                    self.path,
                    err_ub!(InvalidBool(..)) | err_ub!(InvalidUninitBytes(None)) =>
                        { "{}", value } expected { "a boolean" },
                );
                Ok(true)
            }
            ty::Char => {
                let value = self.read_scalar(value)?;
                try_validation!(
                    value.to_char(),
                    self.path,
                    err_ub!(InvalidChar(..)) | err_ub!(InvalidUninitBytes(None)) =>
                        { "{}", value } expected { "a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)" },
                );
                Ok(true)
            }
            ty::Float(_) | ty::Int(_) | ty::Uint(_) => {
                let value = self.read_scalar(value)?;
                // NOTE: Keep this in sync with the array optimization for int/float
                // types below!
                if M::enforce_number_validity(self.ecx) {
                    // Integers/floats in CTFE: Must be scalar bits, pointers are dangerous
                    let is_bits = value.check_init().map_or(false, |v| v.try_to_int().is_ok());
                    if !is_bits {
                        throw_validation_failure!(self.path,
                            { "{}", value } expected { "initialized plain (non-pointer) bytes" }
                        )
                    }
                }
                Ok(true)
            }
            ty::RawPtr(..) => {
                // We are conservative with uninit for integers, but try to
                // actually enforce the strict rules for raw pointers (mostly because
                // that lets us re-use `ref_to_mplace`).
                let place = try_validation!(
                    self.ecx.read_immediate(value).and_then(|ref i| self.ecx.ref_to_mplace(i)),
                    self.path,
                    err_ub!(InvalidUninitBytes(None)) => { "uninitialized raw pointer" },
                    err_unsup!(ReadPointerAsBytes) => { "part of a pointer" } expected { "a proper pointer or integer value" },
                );
                if place.layout.is_unsized() {
                    self.check_wide_ptr_meta(place.meta, place.layout)?;
                }
                Ok(true)
            }
            ty::Ref(_, ty, mutbl) => {
                if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. }))
                    && *mutbl == hir::Mutability::Mut
                {
                    // A mutable reference inside a const? That does not seem right (except if it is
                    // a ZST).
                    let layout = self.ecx.layout_of(ty)?;
                    if !layout.is_zst() {
                        throw_validation_failure!(self.path, { "mutable reference in a `const`" });
                    }
                }
                self.check_safe_pointer(value, "reference")?;
                Ok(true)
            }
            ty::Adt(def, ..) if def.is_box() => {
                self.check_safe_pointer(value, "box")?;
                Ok(true)
            }
            ty::FnPtr(_sig) => {
                let value = try_validation!(
                    self.ecx.read_immediate(value),
                    self.path,
                    err_unsup!(ReadPointerAsBytes) => { "part of a pointer" } expected { "a proper pointer or integer value" },
                );
                // Make sure we print a `ScalarMaybeUninit` (and not an `ImmTy`) in the error
                // message below.
                let value = value.to_scalar_or_uninit();
                let _fn = try_validation!(
                    value.check_init().and_then(|ptr| self.ecx.memory.get_fn(self.ecx.scalar_to_ptr(ptr))),
                    self.path,
                    err_ub!(DanglingIntPointer(..)) |
                    err_ub!(InvalidFunctionPointer(..)) |
                    err_ub!(InvalidUninitBytes(None)) =>
                        { "{}", value } expected { "a function pointer" },
                );
                // FIXME: Check if the signature matches
                Ok(true)
            }
            ty::Never => throw_validation_failure!(self.path, { "a value of the never type `!`" }),
            ty::Foreign(..) | ty::FnDef(..) => {
                // Nothing to check.
                Ok(true)
            }
            // The above should be all the primitive types. The rest is compound, we
            // check them by visiting their fields/variants.
            ty::Adt(..)
            | ty::Tuple(..)
            | ty::Array(..)
            | ty::Slice(..)
            | ty::Str
            | ty::Dynamic(..)
            | ty::Closure(..)
            | ty::Generator(..) => Ok(false),
            // Some types only occur during typechecking, they have no layout.
            // We should not see them here and we could not check them anyway.
            ty::Error(_)
            | ty::Infer(..)
            | ty::Placeholder(..)
            | ty::Bound(..)
            | ty::Param(..)
            | ty::Opaque(..)
            | ty::Projection(..)
            | ty::GeneratorWitness(..) => bug!("Encountered invalid type {:?}", ty),
        }
    }
fn try_visit_primitive ( & mut self , value : & OpTy < ' tcx , M :: PointerTag > , ) -> InterpResult < ' tcx , bool > { // Go over all the primitive types let ty = value . layout . ty ; match ty . kind ( ) { ty :: Bool => { let value = self . read_scalar ( value ) ? ; try_validation ! ( value to_bool ( ) self path err_ub ( InvalidBool ( ) ) err_ub ( InvalidUninitBytes ( None ) ) { " " value } expected { " " } ) ; Ok ( true ) } ty :: Char => { let value = self . read_scalar ( value ) ? ; try_validation ! ( value to_char ( ) self path err_ub ( InvalidChar ( ) ) err_ub ( InvalidUninitBytes ( None ) ) { " " value } expected { " " } ) ; Ok ( true ) } ty :: Float ( _ ) | ty :: Int ( _ ) | ty :: Uint ( _ ) => { let value = self . read_scalar ( value ) ? ; // NOTE: Keep this in sync with the array optimization for int/float // types below! if M :: enforce_number_validity ( self . ecx ) { // Integers/floats in CTFE: Must be scalar bits, pointers are dangerous let is_bits = value . check_init ( ) . map_or ( false , | v | v . try_to_int ( ) . is_ok ( ) ) ; if ! is_bits { throw_validation_failure ! ( self path { " " value } expected { " " } ) } } Ok ( true ) } ty :: RawPtr ( .. ) => { // We are conservative with uninit for integers, but try to // actually enforce the strict rules for raw pointers (mostly because // that lets us re-use `ref_to_mplace`). let place = try_validation ! ( self ecx read_immediate ( value ) and_then ( ref i self ecx ref_to_mplace ( i ) ) self path err_ub ( InvalidUninitBytes ( None ) ) { " " } err_unsup ( ReadPointerAsBytes ) { " " } expected { " " } ) ; if place . layout . is_unsized ( ) { self . check_wide_ptr_meta ( place . meta , place . layout ) ? ; } Ok ( true ) } ty :: Ref ( _ , ty , mutbl ) => { if matches ! ( self ctfe_mode Some ( CtfeValidationMode Const { } ) ) && * mutbl == hir :: Mutability :: Mut { // A mutable reference inside a const? That does not seem right (except if it is // a ZST). let layout = self . ecx . layout_of ( ty ) ? ; if ! layout . is_zst ( ) { throw_validation_failure ! ( self path { " " } ) ; } } self . check_safe_pointer ( value , " " ) ? ; Ok ( true ) } ty :: Adt ( def , .. ) if def . is_box ( ) => { self . check_safe_pointer ( value , " " ) ? ; Ok ( true ) } ty :: FnPtr ( _sig ) => { let value = try_validation ! ( self ecx read_immediate ( value ) self path err_unsup ( ReadPointerAsBytes ) { " " } expected { " " } ) ; // Make sure we print a `ScalarMaybeUninit` (and not an `ImmTy`) in the error // message below. let value = value . to_scalar_or_uninit ( ) ; let _fn = try_validation ! ( value check_init ( ) and_then ( ptr self ecx memory get_fn ( self ecx scalar_to_ptr ( ptr ) ) ) self path err_ub ( DanglingIntPointer ( ) ) err_ub ( InvalidFunctionPointer ( ) ) err_ub ( InvalidUninitBytes ( None ) ) { " " value } expected { " " } ) ; // FIXME: Check if the signature matches Ok ( true ) } ty :: Never => throw_validation_failure ! ( self path { " " } ) , ty :: Foreign ( .. ) | ty :: FnDef ( .. ) => { // Nothing to check. Ok ( true ) } // The above should be all the primitive types. The rest is compound, we // check them by visiting their fields/variants. ty :: Adt ( .. ) | ty :: Tuple ( .. ) | ty :: Array ( .. ) | ty :: Slice ( .. ) | ty :: Str | ty :: Dynamic ( .. ) | ty :: Closure ( .. ) | ty :: Generator ( .. ) => Ok ( false ) , // Some types only occur during typechecking, they have no layout. // We should not see them here and we could not check them anyway. ty :: Error ( _ ) | ty :: Infer ( .. ) | ty :: Placeholder ( .. ) | ty :: Bound ( .. ) | ty :: Param ( .. ) | ty :: Opaque ( .. ) | ty :: Projection ( .. ) | ty :: GeneratorWitness ( .. ) => bug ! ( " " ty ) , } }
Check if this is a value of primitive type, and if yes check the validity of the value
at that type.
Check if this is a value of primitive type and if yes check the validity of the value at that type .
&mut self
value
&OpTy<'tcx, M::PointerTag>