Software 44414 Published by

Rust 1.96.0 finally delivers copyable range types that let developers store slice accessors without fighting the compiler or splitting start and end values. The release also adds assert_matches macros that actually print failing values, which saves hours of debugging compared to wrapping everything in standard assertion calls. WebAssembly builds just got stricter since the linker now rejects undefined symbols outright instead of quietly converting them into env imports. Two registry security patches fix symlink extraction and URL normalization flaws, though crates.io users can safely ignore those particular warnings.



Rust 1.96.0 Brings Copyable Ranges and Stricter WebAssembly Linking

Rust 1.96.0 arrives with a major overhaul for range types that finally allows copying slice accessors, plus new assertion macros that show actual values on failure. The update also tightens WebAssembly linking to catch undefined symbols earlier instead of hiding them as imports. This release fixes long-standing ergonomic issues and patches security holes in third-party registry handling.

New Range Types That Finally Implement Copy

The legacy core::ops range types never implemented Copy, which forced developers to split start and end values whenever they needed cheap storage or cloning. RFC3550 resolves this by introducing new types in core::range that implement IntoIterator rather than Iterator. This design allows the ranges to be copied safely without conflicting with iterator state management.

The stable additions include Range, RangeFrom, and RangeInclusive. These types expose their fields publicly, removing the need to deal with leaked exhausted iterator states that plagued the old RangeInclusive implementation. Code can now wrap a range in a struct and derive Copy without fighting the compiler.

use core::range::Range;

#[derive(Clone, Copy)]
pub struct Span(Range<usize>);

impl Span {
    pub fn of(self, s: &str) -> &str {
        &s[self.0]
    }
}

The syntax 0..1 still produces the legacy types for backward compatibility, but library authors should switch to impl RangeBounds in public APIs to accept both old and new ranges. The standard library will eventually migrate range syntax to the new types in a future edition.

Assert Macros That Print Values on Failure

Debugging pattern matches used to require wrapping code in assert!(matches!(val, pat)). When that assertion failed, the panic message provided no context about what value actually triggered the failure. Rust 1.96 adds assert_matches! and debug_assert_matches! macros that print the Debug representation of the value on failure.

These macros function identically to their wrapped counterparts but save time by showing exactly what went wrong without custom error formatting. They do not appear in the standard prelude because popular third-party crates already define macros with these names, which would cause collisions. Users must import them manually from core or std.

use core::assert_matches;

fn get_random_number() -> u32 {
    4
}

fn main() {
    assert_matches!(get_random_number(), 1..=6);
}

WebAssembly Linker Stops Silently Creating Imports

WebAssembly builds just became stricter. The linker no longer passes --allow-undefined by default, which means undefined symbols now trigger a hard linker error instead of silently converting to imports from the "env" module. This change catches build-time misconfigurations and symbol naming bugs early rather than letting them slip into compiled modules.

Projects that relied on implicit env imports will fail immediately after updating. The old behavior can be restored by setting RUSTFLAGS=-Clink-arg=--allow-undefined or by adding #[link(wasm_import_module = "env")] to the relevant code blocks, but fixing the root cause is the better path. Undefined symbols usually indicate missing definitions or incorrect build scripts that deserve attention rather than workarounds.

Security Patches for Registry Users

Rust 1.96 includes fixes for two vulnerabilities affecting users of third-party package registries. CVE-2026-5223 addresses a medium severity issue involving the extraction of crate tarballs with symlinks, which could potentially lead to file system manipulation during unpacking. CVE-2026-5222 covers a low severity authentication flaw related to normalized URLs that might allow bypasses in certain registry configurations.

Users relying on crates.io remain unaffected by both vulnerabilities. Teams using alternative registries should update their toolchains immediately to mitigate the symlink risk and ensure proper URL normalization during authentication checks.

Announcing Rust 1.96.0 | Rust Blog

Empowering everyone to build reliable and efficient software.

Announcing Rust 1.96.0 | Rust Blog

The update is ready via rustup update stable. Grab the new version and check WebAssembly targets before they start complaining about missing symbols.