From a7e76402a5a3101a509d2eb359f50f962358e3b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Gibrowski=20Fa=C3=A9?= Date: Sat, 27 Dec 2025 11:15:19 -0300 Subject: [PATCH] fix compilation with new new nightly VaList In 2025-12-05, a Rust pull request at https://github.com/rust-lang/rust/pull/141980 reworked the `VaList` implementation to be abi-compatible with C. This broke: * the `printf-compat` implementation, which is fixed in version 0.3 * pretty much every function that methods of `VaList` (most commonly `as_va_list`), since they no longer exist Here, we fix both of those problems and update the compiler version in `rust-toolchain.toml` to be the oldest compiler that will already have this new implementation. Updating the compiler has created 2 unforseen problems: 1. When unwinding, the new Rust version now prints the process's PID. This means for the `c-gull-unwinding` we can no longer use the `assert_cmd` API, as it does not expose the child PID to us. 2. The `c-gull/src/nss.rs` had 3 extra warnings of operations whose results were unused. This was also breaking some other tests. Both of these were also fixed. --- c-gull/src/nss.rs | 3 --- c-scape/Cargo.toml | 2 +- c-scape/src/fs/fcntl.rs | 8 +++--- c-scape/src/stdio.rs | 48 ++++++++++++++------------------- c-scape/src/stdio/chk.rs | 51 +++++++++++++---------------------- rust-toolchain.toml | 2 +- tests/example_crates.rs | 57 +++++++++++++++++++++++++++++++++++----- 7 files changed, 92 insertions(+), 79 deletions(-) diff --git a/c-gull/src/nss.rs b/c-gull/src/nss.rs index 9db12a9..aeee589 100644 --- a/c-gull/src/nss.rs +++ b/c-gull/src/nss.rs @@ -305,10 +305,8 @@ unsafe fn getgr_r( }; let pad = align_of::<*const c_char>() - (buf.addr()) % align_of::<*const c_char>(); buf = buf.add(pad); - buflen -= pad; let gr_mem = buf.cast::<*mut c_char>(); buf = gr_mem.add(num_members + 1).cast::(); - buflen -= buf.addr() - gr_mem.addr(); let mut cur_mem = gr_mem; if num_members != 0 { @@ -319,7 +317,6 @@ unsafe fn getgr_r( buf = buf.add(member.len()); write(buf, 0); buf = buf.add(1); - buflen -= member.len() + 1; } } write(cur_mem, null_mut()); diff --git a/c-scape/Cargo.toml b/c-scape/Cargo.toml index 095c070..f192112 100644 --- a/c-scape/Cargo.toml +++ b/c-scape/Cargo.toml @@ -34,7 +34,7 @@ rand = { version = "0.9.0", default-features = false } rustix-dlmalloc = { version = "0.2.1", optional = true } rustix-openpty = "0.2.0" bitflags = { version = "2.4.1", default-features = false } -printf-compat = { version = "0.2.1", default-features = false } +printf-compat = { version = "0.3.0", default-features = false } num-complex = { version = "0.4.4", default-features = false, features = ["libm"] } posix-regex = { version = "0.1.1", features = ["no_std"] } diff --git a/c-scape/src/fs/fcntl.rs b/c-scape/src/fs/fcntl.rs index 643d6d2..52443e8 100644 --- a/c-scape/src/fs/fcntl.rs +++ b/c-scape/src/fs/fcntl.rs @@ -9,18 +9,16 @@ use libc::c_int; use crate::convert_res; #[no_mangle] -unsafe extern "C" fn fcntl(fd: c_int, cmd: c_int, mut args: ...) -> c_int { - let args = args.as_va_list(); +unsafe extern "C" fn fcntl(fd: c_int, cmd: c_int, args: ...) -> c_int { _fcntl::(fd, cmd, args) } #[no_mangle] -unsafe extern "C" fn fcntl64(fd: c_int, cmd: c_int, mut args: ...) -> c_int { - let args = args.as_va_list(); +unsafe extern "C" fn fcntl64(fd: c_int, cmd: c_int, args: ...) -> c_int { _fcntl::(fd, cmd, args) } -unsafe fn _fcntl(fd: c_int, cmd: c_int, mut args: VaList<'_, '_>) -> c_int { +unsafe fn _fcntl(fd: c_int, cmd: c_int, mut args: VaList<'_>) -> c_int { match cmd { libc::F_GETFL => { libc!(libc::fcntl(fd, libc::F_GETFL)); diff --git a/c-scape/src/stdio.rs b/c-scape/src/stdio.rs index d9d3160..ccc557c 100644 --- a/c-scape/src/stdio.rs +++ b/c-scape/src/stdio.rs @@ -714,30 +714,24 @@ unsafe fn parse_oflags(mode: *const c_char) -> Option { } #[no_mangle] -unsafe extern "C" fn printf(fmt: *const c_char, mut args: ...) -> c_int { - let va_list = args.as_va_list(); - vprintf(fmt, va_list) +unsafe extern "C" fn printf(fmt: *const c_char, args: ...) -> c_int { + vprintf(fmt, args) } #[no_mangle] -unsafe extern "C" fn vprintf(fmt: *const c_char, va_list: VaList<'_, '_>) -> c_int { +unsafe extern "C" fn vprintf(fmt: *const c_char, va_list: VaList<'_>) -> c_int { //libc!(libc::vprintf(fmt, va_list)); vfprintf(stdout, fmt, va_list) } #[no_mangle] -unsafe extern "C" fn sprintf(ptr: *mut c_char, fmt: *const c_char, mut args: ...) -> c_int { - let va_list = args.as_va_list(); - vsprintf(ptr, fmt, va_list) +unsafe extern "C" fn sprintf(ptr: *mut c_char, fmt: *const c_char, args: ...) -> c_int { + vsprintf(ptr, fmt, args) } #[no_mangle] -unsafe extern "C" fn vsprintf( - ptr: *mut c_char, - fmt: *const c_char, - va_list: VaList<'_, '_>, -) -> c_int { +unsafe extern "C" fn vsprintf(ptr: *mut c_char, fmt: *const c_char, va_list: VaList<'_>) -> c_int { //libc!(libc::vsprintf(ptr, fmt, va_list)); let mut out = String::new(); @@ -762,10 +756,9 @@ unsafe extern "C" fn snprintf( ptr: *mut c_char, len: usize, fmt: *const c_char, - mut args: ... + args: ... ) -> c_int { - let va_list = args.as_va_list(); - vsnprintf(ptr, len, fmt, va_list) + vsnprintf(ptr, len, fmt, args) } #[no_mangle] @@ -773,7 +766,7 @@ unsafe extern "C" fn vsnprintf( ptr: *mut c_char, len: usize, fmt: *const c_char, - va_list: VaList<'_, '_>, + va_list: VaList<'_>, ) -> c_int { //libc!(libc::vsnprintf(ptr, len, fmt, va_list)); @@ -797,13 +790,12 @@ unsafe extern "C" fn vsnprintf( } #[no_mangle] -unsafe extern "C" fn dprintf(fd: c_int, fmt: *const c_char, mut args: ...) -> c_int { - let va_list = args.as_va_list(); - vdprintf(fd, fmt, va_list) +unsafe extern "C" fn dprintf(fd: c_int, fmt: *const c_char, args: ...) -> c_int { + vdprintf(fd, fmt, args) } #[no_mangle] -unsafe extern "C" fn vdprintf(fd: c_int, fmt: *const c_char, va_list: VaList<'_, '_>) -> c_int { +unsafe extern "C" fn vdprintf(fd: c_int, fmt: *const c_char, va_list: VaList<'_>) -> c_int { //libc!(libc::vdprintf(fd, fmt, va_list)); let mut out = String::new(); @@ -830,16 +822,15 @@ unsafe extern "C" fn vdprintf(fd: c_int, fmt: *const c_char, va_list: VaList<'_, } #[no_mangle] -unsafe extern "C" fn fprintf(file: *mut libc::FILE, fmt: *const c_char, mut args: ...) -> c_int { - let va_list = args.as_va_list(); - vfprintf(file, fmt, va_list) +unsafe extern "C" fn fprintf(file: *mut libc::FILE, fmt: *const c_char, args: ...) -> c_int { + vfprintf(file, fmt, args) } #[no_mangle] unsafe extern "C" fn vfprintf( file: *mut libc::FILE, fmt: *const c_char, - va_list: VaList<'_, '_>, + va_list: VaList<'_>, ) -> c_int { //libc!(libc::vfprintf(file, fmt, va_list)); @@ -858,9 +849,9 @@ unsafe extern "C" fn vfprintf( unsafe extern "C" fn vasprintf( strp: *mut *mut c_char, fmt: *const c_char, - va_list: VaList<'_, '_>, + va_list: VaList<'_>, ) -> c_int { - let len = va_list.with_copy(|va_list| vsnprintf(null_mut(), 0, fmt, va_list)); + let len = vsnprintf(null_mut(), 0, fmt, va_list.clone()); if len < 0 { return -1; } @@ -875,9 +866,8 @@ unsafe extern "C" fn vasprintf( } #[no_mangle] -unsafe extern "C" fn asprintf(strp: *mut *mut c_char, fmt: *const c_char, mut args: ...) -> c_int { - let va_list = args.as_va_list(); - vasprintf(strp, fmt, va_list) +unsafe extern "C" fn asprintf(strp: *mut *mut c_char, fmt: *const c_char, args: ...) -> c_int { + vasprintf(strp, fmt, args) } #[no_mangle] diff --git a/c-scape/src/stdio/chk.rs b/c-scape/src/stdio/chk.rs index 8ead3d2..f02761a 100644 --- a/c-scape/src/stdio/chk.rs +++ b/c-scape/src/stdio/chk.rs @@ -17,10 +17,9 @@ unsafe extern "C" fn __snprintf_chk( flag: c_int, slen: size_t, fmt: *const c_char, - mut args: ... + args: ... ) -> c_int { - let va_list = args.as_va_list(); - __vsnprintf_chk(ptr, len, flag, slen, fmt, va_list) + __vsnprintf_chk(ptr, len, flag, slen, fmt, args) } // @@ -31,7 +30,7 @@ unsafe extern "C" fn __vsnprintf_chk( flag: c_int, slen: size_t, fmt: *const c_char, - va_list: VaList<'_, '_>, + va_list: VaList<'_>, ) -> c_int { if slen < len { __chk_fail(); @@ -51,10 +50,9 @@ unsafe extern "C" fn __sprintf_chk( flag: c_int, strlen: size_t, format: *const c_char, - mut args: ... + args: ... ) -> c_int { - let va_list = args.as_va_list(); - __vsprintf_chk(ptr, flag, strlen, format, va_list) + __vsprintf_chk(ptr, flag, strlen, format, args) } #[no_mangle] @@ -63,7 +61,7 @@ unsafe extern "C" fn __vsprintf_chk( flag: c_int, strlen: size_t, fmt: *const c_char, - va_list: VaList<'_, '_>, + va_list: VaList<'_>, ) -> c_int { if flag > 0 { unimplemented!("__USE_FORTIFY_LEVEL > 0"); @@ -88,10 +86,9 @@ unsafe extern "C" fn __fprintf_chk( file: *mut libc::FILE, flag: c_int, fmt: *const c_char, - mut args: ... + args: ... ) -> c_int { - let va_list = args.as_va_list(); - __vfprintf_chk(file, flag, fmt, va_list) + __vfprintf_chk(file, flag, fmt, args) } // @@ -100,7 +97,7 @@ unsafe extern "C" fn __vfprintf_chk( file: *mut libc::FILE, flag: c_int, fmt: *const c_char, - va_list: VaList<'_, '_>, + va_list: VaList<'_>, ) -> c_int { if flag > 0 { unimplemented!("__USE_FORTIFY_LEVEL > 0"); @@ -113,17 +110,12 @@ unsafe extern "C" fn __vfprintf_chk( // #[no_mangle] -unsafe extern "C" fn __printf_chk(flag: c_int, fmt: *const c_char, mut args: ...) -> c_int { - let va_list = args.as_va_list(); - __vprintf_chk(flag, fmt, va_list) +unsafe extern "C" fn __printf_chk(flag: c_int, fmt: *const c_char, args: ...) -> c_int { + __vprintf_chk(flag, fmt, args) } #[no_mangle] -unsafe extern "C" fn __vprintf_chk( - flag: c_int, - fmt: *const c_char, - va_list: VaList<'_, '_>, -) -> c_int { +unsafe extern "C" fn __vprintf_chk(flag: c_int, fmt: *const c_char, va_list: VaList<'_>) -> c_int { if flag > 0 { unimplemented!("__USE_FORTIFY_LEVEL > 0"); } @@ -138,10 +130,9 @@ unsafe extern "C" fn __asprintf_chk( strp: *mut *mut c_char, flag: c_int, fmt: *const c_char, - mut args: ... + args: ... ) -> c_int { - let va_list = args.as_va_list(); - __vasprintf_chk(strp, flag, fmt, va_list) + __vasprintf_chk(strp, flag, fmt, args) } #[no_mangle] @@ -149,7 +140,7 @@ unsafe extern "C" fn __vasprintf_chk( strp: *mut *mut c_char, flag: c_int, fmt: *const c_char, - va_list: VaList<'_, '_>, + va_list: VaList<'_>, ) -> c_int { if flag > 0 { unimplemented!("__USE_FORTIFY_LEVEL > 0"); @@ -159,14 +150,8 @@ unsafe extern "C" fn __vasprintf_chk( } #[no_mangle] -unsafe extern "C" fn __dprintf_chk( - fd: c_int, - flag: c_int, - fmt: *const c_char, - mut args: ... -) -> c_int { - let va_list = args.as_va_list(); - __vdprintf_chk(fd, flag, fmt, va_list) +unsafe extern "C" fn __dprintf_chk(fd: c_int, flag: c_int, fmt: *const c_char, args: ...) -> c_int { + __vdprintf_chk(fd, flag, fmt, args) } #[no_mangle] @@ -174,7 +159,7 @@ unsafe extern "C" fn __vdprintf_chk( fd: c_int, flag: c_int, fmt: *const c_char, - va_list: VaList<'_, '_>, + va_list: VaList<'_>, ) -> c_int { if flag > 0 { unimplemented!("__USE_FORTIFY_LEVEL > 0"); diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 7149472..e76255e 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-04-28" +channel = "nightly-2025-12-07" components = ["rustc", "cargo", "rust-std", "rust-src", "rustfmt"] diff --git a/tests/example_crates.rs b/tests/example_crates.rs index 4c38814..17ddf91 100644 --- a/tests/example_crates.rs +++ b/tests/example_crates.rs @@ -140,14 +140,57 @@ fn example_crate_c_scape_unwinding() { #[test] fn example_crate_c_gull_unwinding() { - test_crate( - "c-gull-unwinding", - &[], - &[("RUST_BACKTRACE", "0")], - "Hello, world!\nHello world using libc `printf`!\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, + // Note: Rust's default unwind now prints a message with the process's PID. The assert_cmd + // command does not let us get the child's PID. So we have to use the std::process::Command API + // instead. + use std::process::Command; + use std::process::Stdio; + + #[cfg(target_arch = "x86_64")] + let arch = "x86_64"; + #[cfg(target_arch = "aarch64")] + let arch = "aarch64"; + #[cfg(target_arch = "riscv64")] + let arch = "riscv64gc"; + #[cfg(target_arch = "x86")] + let arch = "i686"; + #[cfg(target_arch = "arm")] + let arch = "armv5te"; + #[cfg(target_env = "gnueabi")] + let env = "gnueabi"; + #[cfg(all(target_env = "gnu", target_abi = "eabi"))] + let env = "gnueabi"; + #[cfg(all(target_env = "gnu", not(target_abi = "eabi")))] + let env = "gnu"; + + let mut command = Command::new("cargo"); + command.arg("run").arg("--quiet"); + command.arg(&format!("--target={}-unknown-linux-{}", arch, env)); + + command.env("RUST_BACKTRACE", "0"); + command.current_dir("example-crates/c-gull-unwinding"); + + command.stdout(Stdio::piped()); + command.stderr(Stdio::piped()); + + let child = command.spawn().unwrap(); + let pid = child.id(); + let output = child.wait_with_output().unwrap(); + + assert_eq!( + std::str::from_utf8(&output.stdout).unwrap(), + "Hello, world!\nHello world using libc `printf`!\n" + ); + assert_eq!( + std::str::from_utf8(&output.stderr).unwrap(), + format!( + "\nthread 'main' ({pid}) panicked at src/main.rs:18:5:\n\ + catch me!\n\ + note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\n" + ) + .as_str() ); + assert!(output.status.success()); } #[test]