Series: The Rust Annals

Vol. I Issue 59 nlopes.dev

Announcing Rust 1.58.0

Stabilizes captured identifiers in format strings (major DX improvement), implements a critical Windows security hardening for process execution, and adds numerous practical standard library methods.

Captured identifiers in format strings

Format strings can now capture arguments simply by writing {ident} in the string. Formats have long accepted positional arguments (optionally by index) and named arguments, for example:

println!("Hello, {}!", get_person());                // implicit position
println!("Hello, {0}!", get_person());               // explicit index
println!("Hello, {person}!", person = get_person()); // named

Now named arguments can also be captured from the surrounding scope, like:

let person = get_person();
// ...
println!("Hello, {person}!"); // captures the local `person`

This may also be used in formatting parameters:

let (width, precision) = get_format();
for (name, score) in get_scores() {
  println!("{name}: {score:width$.precision$}");
}

Format strings can only capture plain identifiers, not arbitrary paths or expressions. For more complicated arguments, either assign them to a local name first, or use the older name = expression style of formatting arguments.

This feature works in all macros accepting format strings. However, one corner case is the panic! macro in 2015 and 2018 editions, where panic!("{ident}") is still treated as an unformatted string – the compiler will warn about this not having the intended effect. Due to the 2021 edition’s update of panic macros for improved consistency, this works as expected in 2021 panic!.

Reduced Windows Command search path

On Windows targets, std::process::Command will no longer search the current directory for executables. That effect was owed to historical behavior of the win32 CreateProcess API, so Rust was effectively searching in this order:

  1. (Rust specific) The directories that are listed in the child’s PATH environment variable, if it was explicitly changed from the parent.
  2. The directory from which the application loaded.
  3. The current directory for the parent process.
  4. The 32-bit Windows system directory.
  5. The 16-bit Windows system directory.
  6. The Windows directory.
  7. The directories that are listed in the PATH environment variable.

However, using the current directory can lead to surprising results, or even malicious behavior when dealing with untrusted directories. For example, ripgrep published CVE-2021-3013 when they learned that their child processes could be intercepted in this way. Even Microsoft’s own PowerShell documents that they do not use the current directory for security.

Rust now performs its own search without the current directory, and the legacy 16-bit directory is also not included, as there is no API to discover its location. So the new Command search order for Rust on Windows is:

  1. The directories that are listed in the child’s PATH environment variable.
  2. The directory from which the application loaded.
  3. The 32-bit Windows system directory.
  4. The Windows directory.
  5. The directories that are listed in the PATH environment variable.

Non-Windows targets continue to use their platform-specific behavior, most often only considering the child or parent PATH environment variable.

More #[must_use] in the standard library

The #[must_use] attribute can be applied to types or functions when failing to explicitly consider them or their output is almost certainly a bug. This has long been used in the standard library for types like Result, which should be checked for error conditions. This also helps catch mistakes such as expecting a function to mutate a value in-place, when it actually returns a new value.

Library proposal 35 was approved in October 2021 to audit and expand the application of #[must_use] throughout the standard library, covering many more functions where the primary effect is the return value. This is similar to the idea of function purity, but looser than a true language feature. Some of these additions were present in release 1.57.0, and now in 1.58.0 the effort has completed.

2015 contributors to this release.

Reproduced from the Rust blog under its publication licence. Typeset in Literata.