Skip to content

Commit 5baed33

Browse files
authored
Use rustix's new uninit buffer support to avoid copies. (#161)
* Use rustix's new uninit buffer support to avoid copies. * Update to the latest nightly. * Update to origin 0.26. * Update naked attribute syntax.
1 parent 9b82b9f commit 5baed33

10 files changed

Lines changed: 38 additions & 86 deletions

File tree

c-gull/src/use_libc.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ macro_rules! checked_cast {
1111
let src_ptr = $ptr;
1212
let target_ptr = src_ptr.cast();
1313

14+
#[allow(unnecessary_transmutes)]
1415
if false {
1516
let target = crate::use_libc::Pad::new(core::ptr::read(target_ptr));
1617

c-scape/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ cc = { version = "1.0.68", optional = true }
2020
[dependencies]
2121
libm = "0.2.1"
2222
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"] }
23-
rustix-futex-sync = { version = "0.3.0", features = ["atomic_usize"] }
23+
rustix-futex-sync = { version = "0.4.0", features = ["atomic_usize"] }
2424
memoffset = "0.9.0"
2525
realpath-ext = { version = "0.1.0", default-features = false }
26-
origin = { version = "0.25.0", default-features = false, features = ["init-fini-arrays", "program-at-exit", "thread-at-exit", "nightly", "getauxval"] }
26+
origin = { version = "0.26.1", default-features = false, features = ["init-fini-arrays", "program-at-exit", "thread-at-exit", "nightly", "getauxval"] }
2727
# We use the libc crate for C ABI types and constants, but we don't depend on
2828
# the actual platform libc.
2929
libc = { version = "0.2.155", default-features = false }

c-scape/src/fs/dir/readdir.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ unsafe extern "C" fn readdir64_r(
4242
d_name: [0; 256],
4343
};
4444
let len = core::cmp::min(256, e.file_name().to_bytes().len());
45-
(*entry).d_name[..len].copy_from_slice(transmute(e.file_name().to_bytes()));
45+
(&mut *entry).d_name[..len].copy_from_slice(transmute(e.file_name().to_bytes()));
4646
*ptr = entry;
4747
0
4848
}
@@ -79,7 +79,7 @@ unsafe extern "C" fn readdir64(dir: *mut libc::DIR) -> *mut libc::dirent64 {
7979
d_name: [0; 256],
8080
};
8181
let len = core::cmp::min(256, e.file_name().to_bytes().len());
82-
(*c_scape_dir).storage.dirent64.d_name[..len]
82+
(&mut *c_scape_dir).storage.dirent64.d_name[..len]
8383
.copy_from_slice(transmute(e.file_name().to_bytes()));
8484
&mut (*c_scape_dir).storage.dirent64
8585
}
@@ -127,7 +127,7 @@ unsafe extern "C" fn readdir(dir: *mut libc::DIR) -> *mut libc::dirent {
127127
};
128128

129129
let len = core::cmp::min(256, e.file_name().to_bytes().len());
130-
(*c_scape_dir).storage.dirent.d_name[..len]
130+
(&mut *c_scape_dir).storage.dirent.d_name[..len]
131131
.copy_from_slice(transmute(e.file_name().to_bytes()));
132132
&mut (*c_scape_dir).storage.dirent
133133
}

c-scape/src/fs/xattr.rs

Lines changed: 25 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
//! Extended attributes.
22
33
use crate::convert_res;
4-
use alloc::vec;
54
use core::ffi::CStr;
6-
use core::ptr::copy_nonoverlapping;
5+
use core::mem::MaybeUninit;
76
use core::slice;
87
use libc::{c_char, c_int, c_void, size_t, ssize_t};
98
use rustix::fd::BorrowedFd;
@@ -20,18 +19,10 @@ unsafe extern "C" fn getxattr(
2019

2120
let path = CStr::from_ptr(path);
2221
let name = CStr::from_ptr(name);
23-
// `slice::from_raw_parts_mut` assumes that the memory is initialized,
24-
// which our C API here doesn't guarantee. Since rustix currently requires
25-
// a slice, use a temporary copy.
26-
let mut buf = vec![0; len];
27-
match convert_res(rustix::fs::getxattr(path, name, &mut buf)) {
28-
Some(size) => {
29-
// If `size` is 0, `value` could be null.
30-
if size != 0 {
31-
copy_nonoverlapping(buf.as_ptr(), value.cast(), size);
32-
}
33-
size as ssize_t
34-
}
22+
let buf = slice::from_raw_parts_mut(value.cast::<MaybeUninit<u8>>(), len);
23+
24+
match convert_res(rustix::fs::getxattr(path, name, buf)) {
25+
Some((init, _uninit)) => init.len() as ssize_t,
3526
None => -1,
3627
}
3728
}
@@ -47,18 +38,10 @@ unsafe extern "C" fn lgetxattr(
4738

4839
let path = CStr::from_ptr(path);
4940
let name = CStr::from_ptr(name);
50-
// `slice::from_raw_parts_mut` assumes that the memory is initialized,
51-
// which our C API here doesn't guarantee. Since rustix currently requires
52-
// a slice, use a temporary copy.
53-
let mut buf = vec![0; len];
54-
match convert_res(rustix::fs::lgetxattr(path, name, &mut buf)) {
55-
Some(size) => {
56-
// If `size` is 0, `value` could be null.
57-
if size != 0 {
58-
copy_nonoverlapping(buf.as_ptr(), value.cast(), size);
59-
}
60-
size as ssize_t
61-
}
41+
let buf = slice::from_raw_parts_mut(value.cast::<MaybeUninit<u8>>(), len);
42+
43+
match convert_res(rustix::fs::lgetxattr(path, name, buf)) {
44+
Some((init, _uninit)) => init.len() as ssize_t,
6245
None => -1,
6346
}
6447
}
@@ -74,18 +57,10 @@ unsafe extern "C" fn fgetxattr(
7457

7558
let fd = BorrowedFd::borrow_raw(fd);
7659
let name = CStr::from_ptr(name);
77-
// `slice::from_raw_parts_mut` assumes that the memory is initialized,
78-
// which our C API here doesn't guarantee. Since rustix currently requires
79-
// a slice, use a temporary copy.
80-
let mut buf = vec![0; len];
81-
match convert_res(rustix::fs::fgetxattr(fd, name, &mut buf)) {
82-
Some(size) => {
83-
// If `size` is 0, `value` could be null.
84-
if size != 0 {
85-
copy_nonoverlapping(buf.as_ptr(), value.cast(), size);
86-
}
87-
size as ssize_t
88-
}
60+
let buf = slice::from_raw_parts_mut(value.cast::<MaybeUninit<u8>>(), len);
61+
62+
match convert_res(rustix::fs::fgetxattr(fd, name, buf)) {
63+
Some((init, _uninit)) => init.len() as ssize_t,
8964
None => -1,
9065
}
9166
}
@@ -155,18 +130,10 @@ unsafe extern "C" fn listxattr(path: *const c_char, list: *mut c_char, len: size
155130
libc!(libc::listxattr(path, list, len));
156131

157132
let path = CStr::from_ptr(path);
158-
// `slice::from_raw_parts_mut` assumes that the memory is initialized,
159-
// which our C API here doesn't guarantee. Since rustix currently requires
160-
// a slice, use a temporary copy.
161-
let mut buf = vec![0; len];
162-
match convert_res(rustix::fs::listxattr(path, &mut buf)) {
163-
Some(size) => {
164-
// If `size` is 0, `value` could be null.
165-
if size != 0 {
166-
copy_nonoverlapping(buf.as_ptr(), list.cast(), size);
167-
}
168-
size as ssize_t
169-
}
133+
let buf = slice::from_raw_parts_mut(list.cast::<MaybeUninit<u8>>(), len);
134+
135+
match convert_res(rustix::fs::listxattr(path, buf)) {
136+
Some((init, _uninit)) => init.len() as ssize_t,
170137
None => -1,
171138
}
172139
}
@@ -176,18 +143,10 @@ unsafe extern "C" fn llistxattr(path: *const c_char, list: *mut c_char, len: siz
176143
libc!(libc::llistxattr(path, list, len));
177144

178145
let path = CStr::from_ptr(path);
179-
// `slice::from_raw_parts_mut` assumes that the memory is initialized,
180-
// which our C API here doesn't guarantee. Since rustix currently requires
181-
// a slice, use a temporary copy.
182-
let mut buf = vec![0; len];
183-
match convert_res(rustix::fs::llistxattr(path, &mut buf)) {
184-
Some(size) => {
185-
// If `size` is 0, `value` could be null.
186-
if size != 0 {
187-
copy_nonoverlapping(buf.as_ptr(), list.cast(), size);
188-
}
189-
size as ssize_t
190-
}
146+
let buf = slice::from_raw_parts_mut(list.cast::<MaybeUninit<u8>>(), len);
147+
148+
match convert_res(rustix::fs::llistxattr(path, buf)) {
149+
Some((init, _uninit)) => init.len() as ssize_t,
191150
None => -1,
192151
}
193152
}
@@ -197,18 +156,10 @@ unsafe extern "C" fn flistxattr(fd: c_int, list: *mut c_char, len: size_t) -> ss
197156
libc!(libc::flistxattr(fd, list, len));
198157

199158
let fd = BorrowedFd::borrow_raw(fd);
200-
// `slice::from_raw_parts_mut` assumes that the memory is initialized,
201-
// which our C API here doesn't guarantee. Since rustix currently requires
202-
// a slice, use a temporary copy.
203-
let mut buf = vec![0; len];
204-
match convert_res(rustix::fs::flistxattr(fd, &mut buf)) {
205-
Some(size) => {
206-
// If `size` is 0, `value` could be null.
207-
if size != 0 {
208-
copy_nonoverlapping(buf.as_ptr(), list.cast(), size);
209-
}
210-
size as ssize_t
211-
}
159+
let buf = slice::from_raw_parts_mut(list.cast::<MaybeUninit<u8>>(), len);
160+
161+
match convert_res(rustix::fs::flistxattr(fd, buf)) {
162+
Some((init, _uninit)) => init.len() as ssize_t,
212163
None => -1,
213164
}
214165
}

c-scape/src/jmp.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ type sigjmp_buf = *mut c_void;
2424
target_arch = "x86_64",
2525
target_arch = "x86"
2626
),
27-
naked
27+
unsafe(naked)
2828
)]
2929
unsafe extern "C" fn setjmp(env: jmp_buf) -> c_int {
3030
//libc!(libc::setjmp(env));
@@ -191,7 +191,7 @@ core::arch::global_asm!(".globl _setjmp", ".set _setjmp, setjmp");
191191
target_arch = "x86_64",
192192
target_arch = "x86"
193193
),
194-
naked
194+
unsafe(naked)
195195
)]
196196
unsafe extern "C" fn longjmp(env: jmp_buf, val: c_int) -> ! {
197197
//libc!(libc::longjmp(env, val));
@@ -358,7 +358,7 @@ core::arch::global_asm!(".globl _longjmp", ".set _longjmp, longjmp");
358358
target_arch = "x86_64",
359359
target_arch = "x86"
360360
),
361-
naked
361+
unsafe(naked)
362362
)]
363363
unsafe extern "C" fn sigsetjmp(_env: sigjmp_buf, _savesigs: c_int) -> c_int {
364364
//libc!(libc::sigsetjmp(env, savesigs));

c-scape/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
#![feature(c_variadic)] // for `printf`, `ioctl`, etc.
77
#![feature(sync_unsafe_cell)] // for lots of libc static variables
88
#![feature(linkage)] // for `malloc` etc.
9-
#![feature(naked_functions)] // for `setjmp` etc.
109
// Disable some common warnings.
1110
#![allow(unexpected_cfgs)]
1211
// Don't warn if `try_into()` is fallible on some targets.

c-scape/src/use_libc.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ macro_rules! checked_cast {
1111
let src_ptr = $ptr;
1212
let target_ptr = src_ptr.cast();
1313

14+
#[allow(unnecessary_transmutes)]
1415
if false {
1516
let target = crate::use_libc::Pad::new(core::ptr::read(target_ptr));
1617

example-crates/c-scape-unwinding/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ package = "c-scape"
2525
errno = { version = "0.3.3", default-features = false }
2626
rustix-dlmalloc = { version = "0.2.1", features = ["global"] }
2727
# Depend on `unwinding` so that we can do `catch_unwind`.
28-
unwinding = { version = "0.2.3", default-features = false, features = ["panic"] }
28+
unwinding = { version = "0.2.6", default-features = false, features = ["panic"] }
2929

3030
# This is just an example crate, and not part of the c-ward workspace.
3131
[workspace]

rust-toolchain.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
[toolchain]
2-
channel = "nightly-2025-01-02"
2+
channel = "nightly-2025-04-28"
33
components = ["rustc", "cargo", "rust-std", "rust-src", "rustfmt"]

tests/example_crates.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ fn example_crate_c_gull_unwinding() {
145145
&[],
146146
&[("RUST_BACKTRACE", "0")],
147147
"Hello, world!\nHello world using libc `printf`!\n",
148-
"thread 'main' panicked at src/main.rs:18:5:\ncatch me!\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\n",
148+
"\nthread 'main' panicked at src/main.rs:18:5:\ncatch me!\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\n",
149149
None,
150150
);
151151
}

0 commit comments

Comments
 (0)