6666use crate :: marker:: DiscriminantKind ;
6767use crate :: marker:: Tuple ;
6868use crate :: mem:: align_of;
69+ use crate :: ub_checks;
6970
7071pub mod mir;
7172pub mod simd;
@@ -2727,147 +2728,6 @@ pub unsafe fn retag_box_to_raw<T: ?Sized, A>(ptr: *mut T) -> *mut T {
27272728// (`transmute` also falls into this category, but it cannot be wrapped due to the
27282729// check that `T` and `U` have the same size.)
27292730
2730- /// Check that the preconditions of an unsafe function are followed. The check is enabled at
2731- /// runtime if debug assertions are enabled when the caller is monomorphized. In const-eval/Miri
2732- /// checks implemented with this macro for language UB are always ignored.
2733- ///
2734- /// This macro should be called as
2735- /// `assert_unsafe_precondition!(check_{library,lang}_ub, "message", (ident: type = expr, ident: type = expr) => check_expr)`
2736- /// where each `expr` will be evaluated and passed in as function argument `ident: type`. Then all
2737- /// those arguments are passed to a function with the body `check_expr`.
2738- /// Pick `check_language_ub` when this is guarding a violation of language UB, i.e., immediate UB
2739- /// according to the Rust Abstract Machine. Pick `check_library_ub` when this is guarding a violation
2740- /// of a documented library precondition that does not *immediately* lead to language UB.
2741- ///
2742- /// If `check_library_ub` is used but the check is actually guarding language UB, the check will
2743- /// slow down const-eval/Miri and we'll get the panic message instead of the interpreter's nice
2744- /// diagnostic, but our ability to detect UB is unchanged.
2745- /// But if `check_language_ub` is used when the check is actually for library UB, the check is
2746- /// omitted in const-eval/Miri and thus if we eventually execute language UB which relies on the
2747- /// library UB, the backtrace Miri reports may be far removed from original cause.
2748- ///
2749- /// These checks are behind a condition which is evaluated at codegen time, not expansion time like
2750- /// [`debug_assert`]. This means that a standard library built with optimizations and debug
2751- /// assertions disabled will have these checks optimized out of its monomorphizations, but if a
2752- /// caller of the standard library has debug assertions enabled and monomorphizes an expansion of
2753- /// this macro, that monomorphization will contain the check.
2754- ///
2755- /// Since these checks cannot be optimized out in MIR, some care must be taken in both call and
2756- /// implementation to mitigate their compile-time overhead. Calls to this macro always expand to
2757- /// this structure:
2758- /// ```ignore (pseudocode)
2759- /// if ::core::intrinsics::check_language_ub() {
2760- /// precondition_check(args)
2761- /// }
2762- /// ```
2763- /// where `precondition_check` is monomorphic with the attributes `#[rustc_nounwind]`, `#[inline]` and
2764- /// `#[rustc_no_mir_inline]`. This combination of attributes ensures that the actual check logic is
2765- /// compiled only once and generates a minimal amount of IR because the check cannot be inlined in
2766- /// MIR, but *can* be inlined and fully optimized by a codegen backend.
2767- ///
2768- /// Callers should avoid introducing any other `let` bindings or any code outside this macro in
2769- /// order to call it. Since the precompiled standard library is built with full debuginfo and these
2770- /// variables cannot be optimized out in MIR, an innocent-looking `let` can produce enough
2771- /// debuginfo to have a measurable compile-time impact on debug builds.
2772- #[ allow_internal_unstable( ub_checks) ] // permit this to be called in stably-const fn
2773- macro_rules! assert_unsafe_precondition {
2774- ( $kind: ident, $message: expr, ( $( $name: ident: $ty: ty = $arg: expr) ,* $( , ) ?) => $e: expr $( , ) ?) => {
2775- {
2776- // #[cfg(bootstrap)] (this comment)
2777- // When the standard library is compiled with debug assertions, we want the check to inline for better performance.
2778- // This is important when working on the compiler, which is compiled with debug assertions locally.
2779- // When not compiled with debug assertions (so the precompiled std) we outline the check to minimize the compile
2780- // time impact when debug assertions are disabled.
2781- // The proper solution to this is the `#[rustc_no_mir_inline]` below, but we still want decent performance for cfg(bootstrap).
2782- #[ cfg_attr( all( debug_assertions, bootstrap) , inline( always) ) ]
2783- #[ cfg_attr( all( not( debug_assertions) , bootstrap) , inline( never) ) ]
2784-
2785- // This check is inlineable, but not by the MIR inliner.
2786- // The reason for this is that the MIR inliner is in an exceptionally bad position
2787- // to think about whether or not to inline this. In MIR, this call is gated behind `debug_assertions`,
2788- // which will codegen to `false` in release builds. Inlining the check would be wasted work in that case and
2789- // would be bad for compile times.
2790- //
2791- // LLVM on the other hand sees the constant branch, so if it's `false`, it can immediately delete it without
2792- // inlining the check. If it's `true`, it can inline it and get significantly better performance.
2793- #[ cfg_attr( not( bootstrap) , rustc_no_mir_inline) ]
2794- #[ cfg_attr( not( bootstrap) , inline) ]
2795- #[ rustc_nounwind]
2796- #[ rustc_const_unstable( feature = "ub_checks" , issue = "none" ) ]
2797- const fn precondition_check( $( $name: $ty) ,* ) {
2798- if !$e {
2799- :: core:: panicking:: panic_nounwind(
2800- concat!( "unsafe precondition(s) violated: " , $message)
2801- ) ;
2802- }
2803- }
2804-
2805- if :: core:: intrinsics:: $kind( ) {
2806- precondition_check( $( $arg, ) * ) ;
2807- }
2808- }
2809- } ;
2810- }
2811- pub ( crate ) use assert_unsafe_precondition;
2812-
2813- /// Checks whether `ptr` is properly aligned with respect to
2814- /// `align_of::<T>()`.
2815- ///
2816- /// In `const` this is approximate and can fail spuriously. It is primarily intended
2817- /// for `assert_unsafe_precondition!` with `check_language_ub`, in which case the
2818- /// check is anyway not executed in `const`.
2819- #[ inline]
2820- pub ( crate ) const fn is_aligned_and_not_null ( ptr : * const ( ) , align : usize ) -> bool {
2821- !ptr. is_null ( ) && ptr. is_aligned_to ( align)
2822- }
2823-
2824- #[ inline]
2825- pub ( crate ) const fn is_valid_allocation_size ( size : usize , len : usize ) -> bool {
2826- let max_len = if size == 0 { usize:: MAX } else { isize:: MAX as usize / size } ;
2827- len <= max_len
2828- }
2829-
2830- /// Checks whether the regions of memory starting at `src` and `dst` of size
2831- /// `count * size` do *not* overlap.
2832- ///
2833- /// Note that in const-eval this function just returns `true` and therefore must
2834- /// only be used with `assert_unsafe_precondition!`, similar to `is_aligned_and_not_null`.
2835- #[ inline]
2836- pub ( crate ) const fn is_nonoverlapping (
2837- src : * const ( ) ,
2838- dst : * const ( ) ,
2839- size : usize ,
2840- count : usize ,
2841- ) -> bool {
2842- #[ inline]
2843- fn runtime ( src : * const ( ) , dst : * const ( ) , size : usize , count : usize ) -> bool {
2844- let src_usize = src. addr ( ) ;
2845- let dst_usize = dst. addr ( ) ;
2846- let Some ( size) = size. checked_mul ( count) else {
2847- crate :: panicking:: panic_nounwind (
2848- "is_nonoverlapping: `size_of::<T>() * count` overflows a usize" ,
2849- )
2850- } ;
2851- let diff = src_usize. abs_diff ( dst_usize) ;
2852- // If the absolute distance between the ptrs is at least as big as the size of the buffer,
2853- // they do not overlap.
2854- diff >= size
2855- }
2856-
2857- #[ inline]
2858- const fn comptime ( _: * const ( ) , _: * const ( ) , _: usize , _: usize ) -> bool {
2859- true
2860- }
2861-
2862- #[ cfg_attr( not( bootstrap) , allow( unused_unsafe) ) ] // on bootstrap bump, remove unsafe block
2863- // SAFETY: This function's precondition is equivalent to that of `const_eval_select`.
2864- // Programs which do not execute UB will only see this function return `true`, which makes the
2865- // const and runtime implementation indistinguishable.
2866- unsafe {
2867- const_eval_select ( ( src, dst, size, count) , comptime, runtime)
2868- }
2869- }
2870-
28712731/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
28722732/// and destination must *not* overlap.
28732733///
@@ -2966,7 +2826,7 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
29662826 pub fn copy_nonoverlapping < T > ( src : * const T , dst : * mut T , count : usize ) ;
29672827 }
29682828
2969- assert_unsafe_precondition ! (
2829+ ub_checks :: assert_unsafe_precondition!(
29702830 check_language_ub,
29712831 "ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \
29722832 and the specified memory ranges do not overlap",
@@ -2977,9 +2837,9 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
29772837 align: usize = align_of:: <T >( ) ,
29782838 count: usize = count,
29792839 ) =>
2980- is_aligned_and_not_null( src, align)
2981- && is_aligned_and_not_null( dst, align)
2982- && is_nonoverlapping( src, dst, size, count)
2840+ ub_checks :: is_aligned_and_not_null( src, align)
2841+ && ub_checks :: is_aligned_and_not_null( dst, align)
2842+ && ub_checks :: is_nonoverlapping( src, dst, size, count)
29832843 ) ;
29842844
29852845 // SAFETY: the safety contract for `copy_nonoverlapping` must be
@@ -3070,7 +2930,7 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
30702930
30712931 // SAFETY: the safety contract for `copy` must be upheld by the caller.
30722932 unsafe {
3073- assert_unsafe_precondition ! (
2933+ ub_checks :: assert_unsafe_precondition!(
30742934 check_language_ub,
30752935 "ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \
30762936 and the specified memory ranges do not overlap",
@@ -3079,8 +2939,8 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
30792939 dst: * mut ( ) = dst as * mut ( ) ,
30802940 align: usize = align_of:: <T >( ) ,
30812941 ) =>
3082- is_aligned_and_not_null( src, align)
3083- && is_aligned_and_not_null( dst, align)
2942+ ub_checks :: is_aligned_and_not_null( src, align)
2943+ && ub_checks :: is_aligned_and_not_null( dst, align)
30842944 ) ;
30852945 copy ( src, dst, count)
30862946 }
@@ -3151,13 +3011,13 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
31513011
31523012 // SAFETY: the safety contract for `write_bytes` must be upheld by the caller.
31533013 unsafe {
3154- assert_unsafe_precondition ! (
3014+ ub_checks :: assert_unsafe_precondition!(
31553015 check_language_ub,
31563016 "ptr::write_bytes requires that the destination pointer is aligned and non-null" ,
31573017 (
31583018 addr: * const ( ) = dst as * const ( ) ,
31593019 align: usize = align_of:: <T >( ) ,
3160- ) => is_aligned_and_not_null( addr, align)
3020+ ) => ub_checks :: is_aligned_and_not_null( addr, align)
31613021 ) ;
31623022 write_bytes ( dst, val, count)
31633023 }
0 commit comments