Skip to content

Deny unsafe_op_in_unsafe_fn by default #801

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions builtins-test-intrinsics/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -649,14 +649,14 @@ fn something_with_a_dtor(f: &dyn Fn()) {
f();
}

#[no_mangle]
#[unsafe(no_mangle)]
#[cfg(not(thumb))]
fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int {
run();
0
}

#[no_mangle]
#[unsafe(no_mangle)]
#[cfg(thumb)]
pub fn _start() -> ! {
run();
Expand All @@ -669,30 +669,30 @@ pub fn _start() -> ! {
extern "C" {}

// ARM targets need these symbols
#[no_mangle]
#[unsafe(no_mangle)]
pub fn __aeabi_unwind_cpp_pr0() {}

#[no_mangle]
#[unsafe(no_mangle)]
pub fn __aeabi_unwind_cpp_pr1() {}

#[cfg(not(any(windows, target_os = "cygwin")))]
#[allow(non_snake_case)]
#[no_mangle]
#[unsafe(no_mangle)]
pub fn _Unwind_Resume() {}

#[cfg(not(any(windows, target_os = "cygwin")))]
#[lang = "eh_personality"]
#[no_mangle]
#[unsafe(no_mangle)]
pub extern "C" fn eh_personality() {}

#[cfg(any(all(windows, target_env = "gnu"), target_os = "cygwin"))]
mod mingw_unwinding {
#[no_mangle]
#[unsafe(no_mangle)]
pub fn rust_eh_personality() {}
#[no_mangle]
#[unsafe(no_mangle)]
pub fn rust_eh_unwind_resume() {}
#[no_mangle]
#[unsafe(no_mangle)]
pub fn rust_eh_register_frames() {}
#[no_mangle]
#[unsafe(no_mangle)]
pub fn rust_eh_unregister_frames() {}
}
181 changes: 148 additions & 33 deletions compiler-builtins/src/arm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,90 +76,205 @@ intrinsics! {
);
}

// FIXME: The `*4` and `*8` variants should be defined as aliases.
// FIXME(arm): The `*4` and `*8` variants should be defined as aliases.

/// `memcpy` provided with the `aapcs` ABI.
///
/// # Safety
///
/// Usual `memcpy` requirements apply.
#[cfg(not(target_vendor = "apple"))]
pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) {
crate::mem::memcpy(dest, src, n);
pub unsafe extern "aapcs" fn __aeabi_memcpy(dst: *mut u8, src: *const u8, n: usize) {
// SAFETY: memcpy preconditions apply.
unsafe { crate::mem::memcpy(dst, src, n) };
}

/// `memcpy` for 4-byte alignment.
///
/// # Safety
///
/// Usual `memcpy` requirements apply. Additionally, `dest` and `src` must be aligned to
/// four bytes.
#[cfg(not(target_vendor = "apple"))]
pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) {
pub unsafe extern "aapcs" fn __aeabi_memcpy4(dst: *mut u8, src: *const u8, n: usize) {
// We are guaranteed 4-alignment, so accessing at u32 is okay.
let mut dest = dest as *mut u32;
let mut src = src as *mut u32;
let mut dst = dst.cast::<u32>();
let mut src = src.cast::<u32>();
debug_assert!(dst.is_aligned());
debug_assert!(src.is_aligned());
let mut n = n;

while n >= 4 {
*dest = *src;
dest = dest.offset(1);
src = src.offset(1);
// SAFETY: `dst` and `src` are both valid for at least 4 bytes, from
// `memcpy` preconditions and the loop guard.
unsafe { *dst = *src };

// FIXME(addr): if we can make this end-of-address-space safe without losing
// performance, we may want to consider that.
// SAFETY: memcpy is not expected to work at the end of the address space
unsafe {
dst = dst.offset(1);
src = src.offset(1);
}

n -= 4;
}

__aeabi_memcpy(dest as *mut u8, src as *const u8, n);
// SAFETY: `dst` and `src` will still be valid for `n` bytes
unsafe { __aeabi_memcpy(dst.cast::<u8>(), src.cast::<u8>(), n) };
}

/// `memcpy` for 8-byte alignment.
///
/// # Safety
///
/// Usual `memcpy` requirements apply. Additionally, `dest` and `src` must be aligned to
/// eight bytes.
#[cfg(not(target_vendor = "apple"))]
pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) {
__aeabi_memcpy4(dest, src, n);
pub unsafe extern "aapcs" fn __aeabi_memcpy8(dst: *mut u8, src: *const u8, n: usize) {
debug_assert!(dst.addr() & 7 == 0);
debug_assert!(src.addr() & 7 == 0);

// SAFETY: memcpy preconditions apply, less strict alignment.
unsafe { __aeabi_memcpy4(dst, src, n) };
}

/// `memmove` provided with the `aapcs` ABI.
///
/// # Safety
///
/// Usual `memmove` requirements apply.
#[cfg(not(target_vendor = "apple"))]
pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) {
crate::mem::memmove(dest, src, n);
pub unsafe extern "aapcs" fn __aeabi_memmove(dst: *mut u8, src: *const u8, n: usize) {
// SAFETY: memmove preconditions apply.
unsafe { crate::mem::memmove(dst, src, n) };
}

/// `memmove` for 4-byte alignment.
///
/// # Safety
///
/// Usual `memmove` requirements apply. Additionally, `dest` and `src` must be aligned to
/// four bytes.
#[cfg(not(any(target_vendor = "apple", target_env = "msvc")))]
pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) {
__aeabi_memmove(dest, src, n);
pub unsafe extern "aapcs" fn __aeabi_memmove4(dst: *mut u8, src: *const u8, n: usize) {
debug_assert!(dst.addr() & 3 == 0);
debug_assert!(src.addr() & 3 == 0);

// SAFETY: same preconditions, less strict aligment.
unsafe { __aeabi_memmove(dst, src, n) };
}

/// `memmove` for 8-byte alignment.
///
/// # Safety
///
/// Usual `memmove` requirements apply. Additionally, `dst` and `src` must be aligned to
/// eight bytes.
#[cfg(not(any(target_vendor = "apple", target_env = "msvc")))]
pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) {
__aeabi_memmove(dest, src, n);
pub unsafe extern "aapcs" fn __aeabi_memmove8(dst: *mut u8, src: *const u8, n: usize) {
debug_assert!(dst.addr() & 7 == 0);
debug_assert!(src.addr() & 7 == 0);

// SAFETY: memmove preconditions apply, less strict alignment.
unsafe { __aeabi_memmove(dst, src, n) };
}

/// `memset` provided with the `aapcs` ABI.
///
/// # Safety
///
/// Usual `memset` requirements apply.
#[cfg(not(target_vendor = "apple"))]
pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) {
pub unsafe extern "aapcs" fn __aeabi_memset(dst: *mut u8, n: usize, c: i32) {
// Note the different argument order
crate::mem::memset(dest, c, n);
// SAFETY: memset preconditions apply.
unsafe { crate::mem::memset(dst, c, n) };
}

/// `memset` for 4-byte alignment.
///
/// # Safety
///
/// Usual `memset` requirements apply. Additionally, `dest` and `src` must be aligned to
/// four bytes.
#[cfg(not(target_vendor = "apple"))]
pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) {
let mut dest = dest as *mut u32;
pub unsafe extern "aapcs" fn __aeabi_memset4(dst: *mut u8, n: usize, c: i32) {
let mut dst = dst.cast::<u32>();
debug_assert!(dst.is_aligned());
let mut n = n;

let byte = (c as u32) & 0xff;
let c = (byte << 24) | (byte << 16) | (byte << 8) | byte;

while n >= 4 {
*dest = c;
dest = dest.offset(1);
// SAFETY: `dst` is valid for at least 4 bytes, from `memset` preconditions and
// the loop guard.
unsafe { *dst = c };

// FIXME(addr): if we can make this end-of-address-space safe without losing
// performance, we may want to consider that.
// SAFETY: memcpy is not expected to work at the end of the address space
unsafe {
dst = dst.offset(1);
}
n -= 4;
}

__aeabi_memset(dest as *mut u8, n, byte as i32);
// SAFETY: `dst` will still be valid for `n` bytes
unsafe { __aeabi_memset(dst.cast::<u8>(), n, byte as i32) };
}

/// `memset` for 8-byte alignment.
///
/// # Safety
///
/// Usual `memset` requirements apply. Additionally, `dst` and `src` must be aligned to
/// eight bytes.
#[cfg(not(target_vendor = "apple"))]
pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) {
__aeabi_memset4(dest, n, c);
pub unsafe extern "aapcs" fn __aeabi_memset8(dst: *mut u8, n: usize, c: i32) {
debug_assert!(dst.addr() & 7 == 0);

// SAFETY: memset preconditions apply, less strict alignment.
unsafe { __aeabi_memset4(dst, n, c) };
}

/// `memclr` provided with the `aapcs` ABI.
///
/// # Safety
///
/// Usual `memclr` requirements apply.
#[cfg(not(target_vendor = "apple"))]
pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) {
__aeabi_memset(dest, n, 0);
pub unsafe extern "aapcs" fn __aeabi_memclr(dst: *mut u8, n: usize) {
// SAFETY: memclr preconditions apply, less strict alignment.
unsafe { __aeabi_memset(dst, n, 0) };
}

/// `memclr` for 4-byte alignment.
///
/// # Safety
///
/// Usual `memclr` requirements apply. Additionally, `dest` and `src` must be aligned to
/// four bytes.
#[cfg(not(any(target_vendor = "apple", target_env = "msvc")))]
pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) {
__aeabi_memset4(dest, n, 0);
pub unsafe extern "aapcs" fn __aeabi_memclr4(dst: *mut u8, n: usize) {
debug_assert!(dst.addr() & 3 == 0);

// SAFETY: memclr preconditions apply, less strict alignment.
unsafe { __aeabi_memset4(dst, n, 0) };
}

/// `memclr` for 8-byte alignment.
///
/// # Safety
///
/// Usual `memclr` requirements apply. Additionally, `dst` and `src` must be aligned to
/// eight bytes.
#[cfg(not(any(target_vendor = "apple", target_env = "msvc")))]
pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) {
__aeabi_memset4(dest, n, 0);
pub unsafe extern "aapcs" fn __aeabi_memclr8(dst: *mut u8, n: usize) {
debug_assert!(dst.addr() & 7 == 0);

// SAFETY: memclr preconditions apply, less strict alignment.
unsafe { __aeabi_memset4(dst, n, 0) };
}
}
3 changes: 3 additions & 0 deletions compiler-builtins/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
#![allow(clippy::manual_swap)]
// Support compiling on both stage0 and stage1 which may differ in supported stable features.
#![allow(stable_features)]
// By default, disallow this as it is forbidden in edition 2024. There is a lot of unsafe code to
// be migrated, however, so exceptions exist.
#![warn(unsafe_op_in_unsafe_fn)]

// We disable #[no_mangle] for tests so that we can verify the test results
// against the native compiler-rt implementations of the builtins.
Expand Down
15 changes: 8 additions & 7 deletions compiler-builtins/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ macro_rules! intrinsics {

#[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), not(feature = "mangled-names")))]
mod $name {
#[no_mangle]
#[unsafe(no_mangle)]
#[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")]
$(#[$($attr)*])*
extern $abi fn $name( $($argname: u16),* ) $(-> $ret)? {
Expand Down Expand Up @@ -292,7 +292,7 @@ macro_rules! intrinsics {

#[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), not(feature = "mangled-names")))]
mod $name {
#[no_mangle]
#[unsafe(no_mangle)]
#[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")]
$(#[$($attr)*])*
extern $abi fn $name( $($argname: $ty),* ) -> u16 {
Expand Down Expand Up @@ -333,7 +333,7 @@ macro_rules! intrinsics {

#[cfg(all(target_arch = "arm", not(feature = "mangled-names")))]
mod $name {
#[no_mangle]
#[unsafe(no_mangle)]
#[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")]
$(#[$($attr)*])*
extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
Expand All @@ -343,7 +343,7 @@ macro_rules! intrinsics {

#[cfg(all(target_arch = "arm", not(feature = "mangled-names")))]
mod $alias {
#[no_mangle]
#[unsafe(no_mangle)]
#[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")]
$(#[$($attr)*])*
extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? {
Expand Down Expand Up @@ -410,7 +410,7 @@ macro_rules! intrinsics {
#[cfg(all(feature = "mem", not(feature = "mangled-names")))]
mod $name {
$(#[$($attr)*])*
#[no_mangle]
#[unsafe(no_mangle)]
#[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")]
unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
super::$name($($argname),*)
Expand Down Expand Up @@ -485,10 +485,11 @@ macro_rules! intrinsics {
#[cfg(not(feature = "mangled-names"))]
mod $name {
$(#[$($attr)*])*
#[no_mangle]
#[unsafe(no_mangle)]
#[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")]
$(unsafe $($empty)?)? extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
super::$name($($argname),*)
// SAFETY: same preconditions.
$(unsafe $($empty)?)? { super::$name($($argname),*) }
}
}

Expand Down
2 changes: 2 additions & 0 deletions compiler-builtins/src/mem/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Trying to satisfy clippy here is hopeless
#![allow(clippy::style)]
// FIXME(e2024): this eventually needs to be removed.
#![allow(unsafe_op_in_unsafe_fn)]

#[allow(warnings)]
#[cfg(target_pointer_width = "16")]
Expand Down
2 changes: 1 addition & 1 deletion compiler-builtins/src/x86_64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ intrinsics! {
// HACK(https://github.com/rust-lang/rust/issues/62785): x86_64-unknown-uefi needs special LLVM
// support unless we emit the _fltused
mod _fltused {
#[no_mangle]
#[unsafe(no_mangle)]
#[used]
#[cfg(target_os = "uefi")]
static _fltused: i32 = 0;
Expand Down