IT

Rust 1.99.0 Released: C Variadics and New Std APIs

Rust 1.99.0 stabilises C-ABI variadic functions, raw-pointer layout helpers and handy new Vec, Box and String APIs.

6 October 2026  ·  5 min read  ·  Anand

Rust 1.99.0 Released: C Variadics and New Std APIs

The Rust project has shipped Rust 1.99.0. The headline feature is long awaited by anyone who writes code that talks to C: you can now define C-style variadic functions in Rust itself, on stable. The release also brings a set of smaller standard library additions that tidy up everyday code around Vec, Box, String and file timestamps. Here is what changed, who benefits, and how to upgrade your toolchains and CI.

Defining C variadic functions in Rust

Variadic functions are the ones that take a variable number of arguments, like printf in C. Rust has long been able to call such functions through FFI, but defining one in Rust that C code could call required nightly features. Rust 1.99.0 stabilises this for the "C" and "C-unwind" ABIs.

A minimal example, adapted from the release announcement:

unsafe extern "C" fn sum(mut args: ...) -> i32 {
    let a = unsafe { args.next_arg::<i32>() };
    let b = unsafe { args.next_arg::<i32>() };
    a + b
}

Alongside this, several supporting pieces are now stable:

  • core::ffi::VaList, a type that is ABI-compatible with C’s va_list, so you can pass argument lists between Rust and C.
  • The VaArgSafe trait, which limits which types may be read out of a VaList, closing off a class of mistakes.
  • Naked variadic functions with non-C ABIs, written using inline assembly, for the low-level cases that need them.

Why it matters: projects that replace C components piece by piece, such as plugin hosts, logging shims, system libraries and drivers, can now implement C interfaces that use variadic signatures directly in Rust, without a C wrapper file in the build. Reading arguments is still unsafe, because Rust cannot check what the caller actually passed, so treat these functions with the same care as any FFI boundary.

Layout information from raw pointers

Three functions for getting the size and alignment of a value through a raw pointer are now stable:

  • Layout::for_value_raw
  • mem::size_of_val_raw
  • mem::align_of_val_raw

They work for both sized and unsized types. This is mainly useful for authors of allocators, smart pointers and other low-level data structures, who previously had to create a reference just to ask how large something was, which is not always valid.

New standard library APIs

The release stabilises a useful batch of everyday APIs:

API What it gives you
Vec::into_parts / Vec::from_parts Take a vector apart into its pointer, length and capacity and rebuild it
Box::into_non_null / Box::from_non_null Convert a box to and from a NonNull pointer
String::from_utf8_lossy_owned Build a String from owned bytes, replacing invalid UTF-8
FromUtf8Error::into_utf8_lossy Recover a lossy string from a failed UTF-8 conversion
VecDeque::retain_back Retain elements, working from the back of the deque
IntoIterator for Box<[T; N]> Iterate a boxed array by value, by reference or mutably
FusedIterator for StepBy<I> Stronger guarantees when chaining step_by
std::fs::set_times / set_times_nofollow Set file timestamps by path, with or without following symlinks

The file timestamp functions will be welcome in deployment tools, backup utilities and build scripts that previously needed an extra crate or a file handle just to adjust modification times.

A note on Box::leak

The documentation for Box::leak now advises against leaking a box and later turning it back into a box, because that pattern interacts badly with compiler optimisations. If you need to hand a heap allocation off and reclaim it later, prefer Box::into_raw or the new Box::into_non_null. It is worth searching your codebase for this pattern during the upgrade.

How to upgrade

If you installed Rust with rustup, upgrading is one command:

rustup update stable
rustc --version

For teams and build servers, a short checklist:

  1. Update pinned toolchains. If your projects use a rust-toolchain.toml file, change the channel to 1.99.0 in a branch first.
  2. Run the full test suite and Clippy. cargo test and cargo clippy --all-targets catch most surprises early.
  3. Update CI images. Docker images and runners that cache a toolchain will not pick up the new release on their own.
  4. Review FFI code. If you kept small C files only to implement variadic callbacks, you can now consider moving them into Rust.
  5. Set MSRV deliberately. If you publish crates and adopt the new APIs, raise your minimum supported Rust version and note it in the changelog.

How TechProvidence can help

We build and maintain CI/CD pipelines, build servers and container images for development teams, including Rust toolchains on Linux. If you would like help standardising toolchain versions across developers and servers, or automating builds and deployments, contact us.

Summary

Rust 1.99.0 is a solid release for systems programmers: stable C variadic definitions make FFI work cleaner, raw-pointer layout helpers help low-level library authors, and the new standard library APIs remove small but common annoyances. Upgrade with rustup, run your tests, and update your CI images.

Source: Rust Blog

Running into something similar?

We look after Linux servers, control panels and virtualization for businesses every day. If an update, vulnerability or outage here affects you, we can help.