From 52d590681e94a2472b03d581258e816ca97dd5f8 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 29 Apr 2025 12:58:02 -0700 Subject: [PATCH 1/9] Use rustix's new uninit buffer support to avoid copies. --- c-scape/src/fs/xattr.rs | 99 +++++++++++------------------------------ 1 file changed, 25 insertions(+), 74 deletions(-) diff --git a/c-scape/src/fs/xattr.rs b/c-scape/src/fs/xattr.rs index b56aae1..5c31431 100644 --- a/c-scape/src/fs/xattr.rs +++ b/c-scape/src/fs/xattr.rs @@ -1,9 +1,8 @@ //! Extended attributes. use crate::convert_res; -use alloc::vec; use core::ffi::CStr; -use core::ptr::copy_nonoverlapping; +use core::mem::MaybeUninit; use core::slice; use libc::{c_char, c_int, c_void, size_t, ssize_t}; use rustix::fd::BorrowedFd; @@ -20,18 +19,10 @@ unsafe extern "C" fn getxattr( let path = CStr::from_ptr(path); let name = CStr::from_ptr(name); - // `slice::from_raw_parts_mut` assumes that the memory is initialized, - // which our C API here doesn't guarantee. Since rustix currently requires - // a slice, use a temporary copy. - let mut buf = vec![0; len]; - match convert_res(rustix::fs::getxattr(path, name, &mut buf)) { - Some(size) => { - // If `size` is 0, `value` could be null. - if size != 0 { - copy_nonoverlapping(buf.as_ptr(), value.cast(), size); - } - size as ssize_t - } + let buf = slice::from_raw_parts_mut(value.cast::>(), len); + + match convert_res(rustix::fs::getxattr(path, name, buf)) { + Some((init, _uninit)) => init.len() as ssize_t, None => -1, } } @@ -47,18 +38,10 @@ unsafe extern "C" fn lgetxattr( let path = CStr::from_ptr(path); let name = CStr::from_ptr(name); - // `slice::from_raw_parts_mut` assumes that the memory is initialized, - // which our C API here doesn't guarantee. Since rustix currently requires - // a slice, use a temporary copy. - let mut buf = vec![0; len]; - match convert_res(rustix::fs::lgetxattr(path, name, &mut buf)) { - Some(size) => { - // If `size` is 0, `value` could be null. - if size != 0 { - copy_nonoverlapping(buf.as_ptr(), value.cast(), size); - } - size as ssize_t - } + let buf = slice::from_raw_parts_mut(value.cast::>(), len); + + match convert_res(rustix::fs::lgetxattr(path, name, buf)) { + Some((init, _uninit)) => init.len() as ssize_t, None => -1, } } @@ -74,18 +57,10 @@ unsafe extern "C" fn fgetxattr( let fd = BorrowedFd::borrow_raw(fd); let name = CStr::from_ptr(name); - // `slice::from_raw_parts_mut` assumes that the memory is initialized, - // which our C API here doesn't guarantee. Since rustix currently requires - // a slice, use a temporary copy. - let mut buf = vec![0; len]; - match convert_res(rustix::fs::fgetxattr(fd, name, &mut buf)) { - Some(size) => { - // If `size` is 0, `value` could be null. - if size != 0 { - copy_nonoverlapping(buf.as_ptr(), value.cast(), size); - } - size as ssize_t - } + let buf = slice::from_raw_parts_mut(value.cast::>(), len); + + match convert_res(rustix::fs::fgetxattr(fd, name, buf)) { + Some((init, _uninit)) => init.len() as ssize_t, None => -1, } } @@ -155,18 +130,10 @@ unsafe extern "C" fn listxattr(path: *const c_char, list: *mut c_char, len: size libc!(libc::listxattr(path, list, len)); let path = CStr::from_ptr(path); - // `slice::from_raw_parts_mut` assumes that the memory is initialized, - // which our C API here doesn't guarantee. Since rustix currently requires - // a slice, use a temporary copy. - let mut buf = vec![0; len]; - match convert_res(rustix::fs::listxattr(path, &mut buf)) { - Some(size) => { - // If `size` is 0, `value` could be null. - if size != 0 { - copy_nonoverlapping(buf.as_ptr(), list.cast(), size); - } - size as ssize_t - } + let buf = slice::from_raw_parts_mut(list.cast::>(), len); + + match convert_res(rustix::fs::listxattr(path, buf)) { + Some((init, _uninit)) => init.len() as ssize_t, None => -1, } } @@ -176,18 +143,10 @@ unsafe extern "C" fn llistxattr(path: *const c_char, list: *mut c_char, len: siz libc!(libc::llistxattr(path, list, len)); let path = CStr::from_ptr(path); - // `slice::from_raw_parts_mut` assumes that the memory is initialized, - // which our C API here doesn't guarantee. Since rustix currently requires - // a slice, use a temporary copy. - let mut buf = vec![0; len]; - match convert_res(rustix::fs::llistxattr(path, &mut buf)) { - Some(size) => { - // If `size` is 0, `value` could be null. - if size != 0 { - copy_nonoverlapping(buf.as_ptr(), list.cast(), size); - } - size as ssize_t - } + let buf = slice::from_raw_parts_mut(list.cast::>(), len); + + match convert_res(rustix::fs::llistxattr(path, buf)) { + Some((init, _uninit)) => init.len() as ssize_t, None => -1, } } @@ -197,18 +156,10 @@ unsafe extern "C" fn flistxattr(fd: c_int, list: *mut c_char, len: size_t) -> ss libc!(libc::flistxattr(fd, list, len)); let fd = BorrowedFd::borrow_raw(fd); - // `slice::from_raw_parts_mut` assumes that the memory is initialized, - // which our C API here doesn't guarantee. Since rustix currently requires - // a slice, use a temporary copy. - let mut buf = vec![0; len]; - match convert_res(rustix::fs::flistxattr(fd, &mut buf)) { - Some(size) => { - // If `size` is 0, `value` could be null. - if size != 0 { - copy_nonoverlapping(buf.as_ptr(), list.cast(), size); - } - size as ssize_t - } + let buf = slice::from_raw_parts_mut(list.cast::>(), len); + + match convert_res(rustix::fs::flistxattr(fd, buf)) { + Some((init, _uninit)) => init.len() as ssize_t, None => -1, } } From e6a295c24bf7873eb618b367d365f159509550fe Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 29 Apr 2025 13:00:12 -0700 Subject: [PATCH 2/9] Update to the latest nightly. --- example-crates/c-scape-unwinding/Cargo.toml | 2 +- rust-toolchain.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example-crates/c-scape-unwinding/Cargo.toml b/example-crates/c-scape-unwinding/Cargo.toml index b85603a..f4accd4 100644 --- a/example-crates/c-scape-unwinding/Cargo.toml +++ b/example-crates/c-scape-unwinding/Cargo.toml @@ -25,7 +25,7 @@ package = "c-scape" errno = { version = "0.3.3", default-features = false } rustix-dlmalloc = { version = "0.2.1", features = ["global"] } # Depend on `unwinding` so that we can do `catch_unwind`. -unwinding = { version = "0.2.3", default-features = false, features = ["panic"] } +unwinding = { version = "0.2.6", default-features = false, features = ["panic"] } # This is just an example crate, and not part of the c-ward workspace. [workspace] diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 1a27b4e..7149472 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-01-02" +channel = "nightly-2025-04-28" components = ["rustc", "cargo", "rust-std", "rust-src", "rustfmt"] From 009b5056d49c7e16440f9ed064dd42300be94f64 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 29 Apr 2025 13:00:53 -0700 Subject: [PATCH 3/9] Update to origin 0.26. --- c-scape/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c-scape/Cargo.toml b/c-scape/Cargo.toml index f44f256..b816a4c 100644 --- a/c-scape/Cargo.toml +++ b/c-scape/Cargo.toml @@ -23,7 +23,7 @@ rustix = { version = "1.0.0", default-features = false, features = ["event", "fs rustix-futex-sync = { version = "0.3.0", features = ["atomic_usize"] } memoffset = "0.9.0" realpath-ext = { version = "0.1.0", default-features = false } -origin = { version = "0.25.0", default-features = false, features = ["init-fini-arrays", "program-at-exit", "thread-at-exit", "nightly", "getauxval"] } +origin = { version = "0.26.0", default-features = false, features = ["init-fini-arrays", "program-at-exit", "thread-at-exit", "nightly", "getauxval"] } # We use the libc crate for C ABI types and constants, but we don't depend on # the actual platform libc. libc = { version = "0.2.155", default-features = false } From 9ff8b0a4e7f88c92ec10c498586ce971e0f0879d Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 29 Apr 2025 13:01:51 -0700 Subject: [PATCH 4/9] Update naked attribute syntax. --- c-scape/src/jmp.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/c-scape/src/jmp.rs b/c-scape/src/jmp.rs index c22572a..34c7f3f 100644 --- a/c-scape/src/jmp.rs +++ b/c-scape/src/jmp.rs @@ -24,7 +24,7 @@ type sigjmp_buf = *mut c_void; target_arch = "x86_64", target_arch = "x86" ), - naked + unsafe(naked) )] unsafe extern "C" fn setjmp(env: jmp_buf) -> c_int { //libc!(libc::setjmp(env)); @@ -191,7 +191,7 @@ core::arch::global_asm!(".globl _setjmp", ".set _setjmp, setjmp"); target_arch = "x86_64", target_arch = "x86" ), - naked + unsafe(naked) )] unsafe extern "C" fn longjmp(env: jmp_buf, val: c_int) -> ! { //libc!(libc::longjmp(env, val)); @@ -358,7 +358,7 @@ core::arch::global_asm!(".globl _longjmp", ".set _longjmp, longjmp"); target_arch = "x86_64", target_arch = "x86" ), - naked + unsafe(naked) )] unsafe extern "C" fn sigsetjmp(_env: sigjmp_buf, _savesigs: c_int) -> c_int { //libc!(libc::sigsetjmp(env, savesigs)); From f3444e468ffd674ca2bf66ee31afe8fbb3523180 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 29 Apr 2025 13:13:34 -0700 Subject: [PATCH 5/9] Updates. --- c-scape/Cargo.toml | 2 +- c-scape/src/lib.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/c-scape/Cargo.toml b/c-scape/Cargo.toml index b816a4c..657e1b3 100644 --- a/c-scape/Cargo.toml +++ b/c-scape/Cargo.toml @@ -23,7 +23,7 @@ rustix = { version = "1.0.0", default-features = false, features = ["event", "fs rustix-futex-sync = { version = "0.3.0", features = ["atomic_usize"] } memoffset = "0.9.0" realpath-ext = { version = "0.1.0", default-features = false } -origin = { version = "0.26.0", default-features = false, features = ["init-fini-arrays", "program-at-exit", "thread-at-exit", "nightly", "getauxval"] } +origin = { version = "0.26.1", default-features = false, features = ["init-fini-arrays", "program-at-exit", "thread-at-exit", "nightly", "getauxval"] } # We use the libc crate for C ABI types and constants, but we don't depend on # the actual platform libc. libc = { version = "0.2.155", default-features = false } diff --git a/c-scape/src/lib.rs b/c-scape/src/lib.rs index 18c9952..9485030 100644 --- a/c-scape/src/lib.rs +++ b/c-scape/src/lib.rs @@ -6,7 +6,6 @@ #![feature(c_variadic)] // for `printf`, `ioctl`, etc. #![feature(sync_unsafe_cell)] // for lots of libc static variables #![feature(linkage)] // for `malloc` etc. -#![feature(naked_functions)] // for `setjmp` etc. // Disable some common warnings. #![allow(unexpected_cfgs)] // Don't warn if `try_into()` is fallible on some targets. From ea33b8b63f0d2663ce7dae9170f5e31f46684bc6 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 29 Apr 2025 13:20:01 -0700 Subject: [PATCH 6/9] Fix more warnings. --- c-gull/src/use_libc.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/c-gull/src/use_libc.rs b/c-gull/src/use_libc.rs index 9ba726d..d370f5a 100644 --- a/c-gull/src/use_libc.rs +++ b/c-gull/src/use_libc.rs @@ -11,6 +11,7 @@ macro_rules! checked_cast { let src_ptr = $ptr; let target_ptr = src_ptr.cast(); + #[allow(unnecessary_transmutes)] if false { let target = crate::use_libc::Pad::new(core::ptr::read(target_ptr)); From b7ed5fa555c0560fbd1db1068e6c3e236f0d1ba3 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 29 Apr 2025 13:23:03 -0700 Subject: [PATCH 7/9] Fix warnings. --- c-scape/src/use_libc.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/c-scape/src/use_libc.rs b/c-scape/src/use_libc.rs index 9ba726d..d370f5a 100644 --- a/c-scape/src/use_libc.rs +++ b/c-scape/src/use_libc.rs @@ -11,6 +11,7 @@ macro_rules! checked_cast { let src_ptr = $ptr; let target_ptr = src_ptr.cast(); + #[allow(unnecessary_transmutes)] if false { let target = crate::use_libc::Pad::new(core::ptr::read(target_ptr)); From c5cc05e269b8d37d717a38d412d464f31277eb1b Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 29 Apr 2025 13:38:03 -0700 Subject: [PATCH 8/9] Fixes. --- c-scape/Cargo.toml | 2 +- c-scape/src/fs/dir/readdir.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/c-scape/Cargo.toml b/c-scape/Cargo.toml index 657e1b3..2eca94a 100644 --- a/c-scape/Cargo.toml +++ b/c-scape/Cargo.toml @@ -20,7 +20,7 @@ cc = { version = "1.0.68", optional = true } [dependencies] libm = "0.2.1" rustix = { version = "1.0.0", default-features = false, features = ["event", "fs", "mm", "net", "param", "pipe", "process", "pty", "rand", "runtime", "shm", "stdio", "system", "termios", "thread", "time"] } -rustix-futex-sync = { version = "0.3.0", features = ["atomic_usize"] } +rustix-futex-sync = { version = "0.4.0", features = ["atomic_usize"] } memoffset = "0.9.0" realpath-ext = { version = "0.1.0", default-features = false } origin = { version = "0.26.1", default-features = false, features = ["init-fini-arrays", "program-at-exit", "thread-at-exit", "nightly", "getauxval"] } diff --git a/c-scape/src/fs/dir/readdir.rs b/c-scape/src/fs/dir/readdir.rs index e180914..9256a8e 100644 --- a/c-scape/src/fs/dir/readdir.rs +++ b/c-scape/src/fs/dir/readdir.rs @@ -42,7 +42,7 @@ unsafe extern "C" fn readdir64_r( d_name: [0; 256], }; let len = core::cmp::min(256, e.file_name().to_bytes().len()); - (*entry).d_name[..len].copy_from_slice(transmute(e.file_name().to_bytes())); + (&mut *entry).d_name[..len].copy_from_slice(transmute(e.file_name().to_bytes())); *ptr = entry; 0 } @@ -79,7 +79,7 @@ unsafe extern "C" fn readdir64(dir: *mut libc::DIR) -> *mut libc::dirent64 { d_name: [0; 256], }; let len = core::cmp::min(256, e.file_name().to_bytes().len()); - (*c_scape_dir).storage.dirent64.d_name[..len] + (&mut *c_scape_dir).storage.dirent64.d_name[..len] .copy_from_slice(transmute(e.file_name().to_bytes())); &mut (*c_scape_dir).storage.dirent64 } @@ -127,7 +127,7 @@ unsafe extern "C" fn readdir(dir: *mut libc::DIR) -> *mut libc::dirent { }; let len = core::cmp::min(256, e.file_name().to_bytes().len()); - (*c_scape_dir).storage.dirent.d_name[..len] + (&mut *c_scape_dir).storage.dirent.d_name[..len] .copy_from_slice(transmute(e.file_name().to_bytes())); &mut (*c_scape_dir).storage.dirent } From 11cc2fea2b0927957a7c1365b0c37a9a9a02497c Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 29 Apr 2025 13:44:36 -0700 Subject: [PATCH 9/9] Update expected test output. --- tests/example_crates.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/example_crates.rs b/tests/example_crates.rs index 8050915..4c38814 100644 --- a/tests/example_crates.rs +++ b/tests/example_crates.rs @@ -145,7 +145,7 @@ fn example_crate_c_gull_unwinding() { &[], &[("RUST_BACKTRACE", "0")], "Hello, world!\nHello world using libc `printf`!\n", - "thread 'main' panicked at src/main.rs:18:5:\ncatch me!\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\n", + "\nthread 'main' panicked at src/main.rs:18:5:\ncatch me!\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\n", None, ); }