惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Project Zero
Project Zero
Security Archives - TechRepublic
Security Archives - TechRepublic
C
Cyber Attacks, Cyber Crime and Cyber Security
Security Latest
Security Latest
Scott Helme
Scott Helme
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
V
Vulnerabilities – Threatpost
C
CERT Recently Published Vulnerability Notes
S
Schneier on Security
G
GRAHAM CLULEY
L
Lohrmann on Cybersecurity
D
Darknet – Hacking Tools, Hacker News & Cyber Security
I
Intezer
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
F
Full Disclosure
T
The Exploit Database - CXSecurity.com
P
Proofpoint News Feed
WordPress大学
WordPress大学
Microsoft Azure Blog
Microsoft Azure Blog
H
Help Net Security
大猫的无限游戏
大猫的无限游戏
MyScale Blog
MyScale Blog
Hacker News: Ask HN
Hacker News: Ask HN
G
Google Developers Blog
H
Heimdal Security Blog
O
OpenAI News
Hugging Face - Blog
Hugging Face - Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
L
LangChain Blog
C
Cisco Blogs
云风的 BLOG
云风的 BLOG
IT之家
IT之家
Cyberwarzone
Cyberwarzone
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Know Your Adversary
Know Your Adversary
博客园 - 聂微东
The Cloudflare Blog
C
Check Point Blog
K
Kaspersky official blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
月光博客
月光博客
T
Tor Project blog
T
Threat Research - Cisco Blogs
T
Tailwind CSS Blog
P
Proofpoint News Feed
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
A
About on SuperTechFans
小众软件
小众软件
Cloudbric
Cloudbric
A
Arctic Wolf

Rust Blog

Security Advisory for Cargo (CVE-2026-5223) | Rust Blog Security Advisory for Cargo (CVE-2026-5222) | Rust Blog Project goals update — April 2026 (end of 2025H2) | Rust Blog Rust is participating in Outreachy | Rust Blog Raising the baseline for the `nvptx64-nvidia-cuda` target | Rust Blog Announcing Google Summer of Code 2026 selected projects | Rust Blog Announcing Rust 1.95.0 | Rust Blog docs.rs: building fewer targets by default | Rust Blog Changes to WebAssembly targets and handling undefined symbols | Rust Blog Announcing Rust 1.94.1 | Rust Blog Security advisory for Cargo | Rust Blog What we heard about Rust's challenges | Rust Blog Call for Testing: Build Dir Layout v2 | Rust Blog Announcing rustup 1.29.0 | Rust Blog Announcing Rust 1.94.0 | Rust Blog 2025 State of Rust Survey Results | Rust Blog Rust debugging survey 2026 | Rust Blog Update on the October 15, 2018 incident on crates.io Announcing Rust 1.29.2 Announcing Rust 1.29 Announcing Rust 1.28 What is Rust 2018? Announcing Rust 1.27.2 Announcing Rust 1.27.1 Security Advisory for rustdoc Announcing Rust 1.27 Announcing Rust 1.26.2 Announcing Rust 1.26.1 Rust turns three Announcing Rust 1.26 The Rust Team All Hands in Berlin: a Recap Increasing Rust’s Reach 2018 Announcing Rust 1.25 Rust's 2018 roadmap Announcing Rust 1.24.1 Announcing Rust 1.24 The 2018 Rust Event Lineup Announcing Rust 1.23 New Year's Rust: A Call for Community Blogposts Rust in 2017: what we achieved Announcing Rust 1.22 (and 1.22.1) Fearless Concurrency in Firefox Quantum Announcing Rust 1.21 impl Future for Rust Rust 2017 Survey Results Announcing Rust 1.20 Announcing Rust 1.19 The 2017 Rust Conference Lineup Rust's 2017 roadmap, six months in Increasing Rust’s Reach Announcing Rust 1.18 Two years of Rust The Rust Libz Blitz Launching the 2017 State of Rust Survey Announcing Rust 1.17 Announcing Rust 1.16 Rust's language ergonomics initiative Announcing Rust 1.15.1 Rust's 2017 roadmap Announcing Rust 1.15 Announcing Rust 1.14 Announcing the First Underhanded Rust Contest Announcing Rust 1.13 Announcing Rust 1.12.1 Announcing Rust 1.12 Incremental Compilation Announcing Rust 1.11 Shape of errors to come The 2016 Rust Conference Lineup Announcing Rust 1.10 State of Rust Survey 2016 Announcing Rust 1.9 One year of Rust Taking Rust everywhere with rustup Launching the 2016 State of Rust Survey Cargo: predictable dependency management Introducing MIR Announcing Rust 1.8 Announcing Rust 1.7 Announcing Rust 1.6 Announcing Rust 1.5 Announcing Rust 1.4 Announcing Rust 1.3 Rust in 2016 Announcing Rust 1.2 Rust 1.1 stable, the Community Subteam, and RustCamp Announcing Rust 1.0 Abstraction without overhead: traits in Rust Rust Once, Run Everywhere Mixing matching, mutation, and moves in Rust Fearless Concurrency with Rust Announcing Rust 1.0 Beta Announcing Rust 1.0.0.alpha.2 Rust 1.0: status report and final timeline Announcing Rust 1.0 Alpha Rust 1.0: Scheduling the trains Yehuda Katz and Steve Klabnik are joining the Rust Core Team Cargo: Rust's community crate host Stability as a Deliverable Road to Rust 1.0
Improving async-await's "Future is not Send" diagnostic | Inside Rust Blog
David Wood on behalf of the Async Foundations WG · 2019-10-11 · via Rust Blog

Async-await is due to hit stable in the 1.39 release (only a month away!), and as announced in the "Async Foundations Update: Time for polish!" post last month, the Async Foundations WG has shifted its focus to polish. This post will highlight one aspect of that focus, diagnostic improvements, and in particular, the improvements that the working group has been making to the once-unhelpful "future is not send" diagnostic.

Why doesn't my future implement Send?

One of the major places where async-await should be a pleasure to use is in multithreaded contexts, where having a future that can be sent to other threads is desirable. This might look something like the following (for brevity, there aren't any threads here, just a requirement that the future implement std::marker::Send):

use std::sync::{Mutex, MutexGuard};

fn is_send<T: Send>(t: T) { }

async fn foo() {
    bar(&Mutex::new(22)).await
}

async fn bar(x: &Mutex<u32>) {
    let g = x.lock().unwrap();
    baz().await
}

async fn baz() { }

fn main() {
    is_send(foo());
}

When we try to compile this, we'll get an unwieldy and hard-to-follow diagnostic:

error[E0277]: `std::sync::MutexGuard<'_, u32>` cannot be sent between threads safely
  --> src/main.rs:23:5
   |
23 |     is_send(foo());
   |     ^^^^^^^ `std::sync::MutexGuard<'_, u32>` cannot be sent between threads safely
   |
   = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::sync::MutexGuard<'_, u32>`
   = note: required because it appears within the type `for<'r, 's> {&'r std::sync::Mutex<u32>, std::sync::MutexGuard<'s, u32>, impl std::future::Future, ()}`
   = note: required because it appears within the type `[static generator@src/main.rs:13:30: 16:2 x:&std::sync::Mutex<u32> for<'r, 's> {&'r std::sync::Mutex<u32>, std::sync::MutexGuard<'s, u32>, impl std::future::Future, ()}]`
   = note: required because it appears within the type `std::future::GenFuture<[static generator@src/main.rs:13:30: 16:2 x:&std::sync::Mutex<u32> for<'r, 's> {&'r std::sync::Mutex<u32>, std::sync::MutexGuard<'s, u32>, impl std::future::Future, ()}]>`
   = note: required because it appears within the type `impl std::future::Future`
   = note: required because it appears within the type `impl std::future::Future`
   = note: required because it appears within the type `for<'r> {impl std::future::Future, ()}`
   = note: required because it appears within the type `[static generator@src/main.rs:9:16: 11:2 for<'r> {impl std::future::Future, ()}]`
   = note: required because it appears within the type `std::future::GenFuture<[static generator@src/main.rs:9:16: 11:2 for<'r> {impl std::future::Future, ()}]>`
   = note: required because it appears within the type `impl std::future::Future`
   = note: required because it appears within the type `impl std::future::Future`
note: required by `is_send`
  --> src/main.rs:5:1
   |
5  | fn is_send<T: Send>(t: T) {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^

That's.. not great. Let's break down what's happening and understand what this error is trying to tell us.

fn main() {
    is_send(foo());
}

In main, we are calling foo and passing the return value to is_send. foo is an async fn, so it doesn't return () (what you might expect for a function with no return type specified). Instead, it returns impl std::future::Future<Output = ()>, some unnamed type that implements std::future::Future:

async fn foo() {
    bar(&Mutex::new(22)).await
}

// becomes...

fn foo() -> impl std::future::Future<Output = ()> {
    async move {
        bar(&Mutex::new(22)).await
    }
}

If you want to learn more about the transformations that happen with async-await, consider reading the async/.await primer chapter of the async book.

fn is_send<T: Send>(t: T) { }

It looks like the error we're getting is because the future returned by foo doesn't satisfy the T: Send bound of is_send.

How are async functions implemented?

To explain why our future doesn't implement Send, we first need to understand a little bit more about what async-await is doing under the hood. rustc implements async fns using generators, an unstable language feature for resumable functions like the co-routines you might be familiar with from other languages. Generators are laid out like enums with variants containing all of the variables that are used across await points (which desugar to generator yields):

async fn bar(x: &Mutex<u32>) {
    let g = x.lock().unwrap();
    baz().await // <- await point (suspend #0), `g` and `x` are in use before await point
} // <- `g` and `x` dropped here, after await point
enum BarGenerator {
    // `bar`'s parameters.
    Unresumed { x: &Mutex<u32> },

    Suspend0 {
        // Future returned by `baz`, which is being polled.
        baz_future: BazGenerator,

        // Locals that are used across the await point.
        x: &Mutex<u32>,
        g: MutexGuard<'_, u32>,
    },

    Returned { value: () }
}

If you want to learn more about the async fn implementation details, then Tyler Mandry has written an excellent blog post diving into their work here in more depth which is definitely worth a read.

So, why doesn't my future implement Send?

We now know that an async fn is represented like an enum behind-the-scenes. In synchronous Rust, you'll be used to your types automatically implementing Send when the compiler determines it's appropriate - typically when all of the fields of your type also implement Send. It follows that the enum-like that represents our async fn would implement Send if all of the types in it do.

In other words, a future is safe to send across threads if all of the types that are held across .await points implement Send. This behaviour is useful because it lets us write generic code that interoperates smoothly with async-await, but without diagnostic support we get confusing error messages.

Well, which type is the problem in the example?

Returning to our example, the future must be holding a type across an .await point that doesn't implement Send, but where? This is the primary question that the diagnostic improvement aims to help answer. Let's start by looking at foo:

async fn foo() {
    bar(&Mutex::new(22)).await
}

foo invokes bar, passing a reference to a std::sync::Mutex and getting a future back, before awaiting it.

async fn bar(x: &Mutex<u32>) {
    let g: MutexGuard<u32> = x.lock().unwrap();
    baz().await
} // <- `g` is dropped here

bar locks the mutex before awaiting baz. std::sync::MutexGuard<u32> does not implement Send and lives across the baz().await point (because g is dropped at the end of the scope) which causes the entire future not to implement Send.

That wasn't obvious from the error: we had to know that futures might implement Send depending on the types they capture and find the type which lives across an await point ourselves.

Fortunately, the Async Foundations WG has been working to improve this error, and in nightly, we see the following diagnostic instead:

error[E0277]: `std::sync::MutexGuard<'_, u32>` cannot be sent between threads safely
  --> src/main.rs:23:5
   |
5  | fn is_send<T: Send>(t: T) {
   |    -------    ---- required by this bound in `is_send`
...
23 |     is_send(foo());
   |     ^^^^^^^ `std::sync::MutexGuard<'_, u32>` cannot be sent between threads safely
   |
   = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::sync::MutexGuard<'_, u32>`
note: future does not implement `std::marker::Send` as this value is used across an await
  --> src/main.rs:15:3
   |
14 |   let g = x.lock().unwrap();
   |       - has type `std::sync::MutexGuard<'_, u32>`
15 |   baz().await;
   |   ^^^^^^^^^^^ await occurs here, with `g` maybe used later
16 | }
   | - `g` is later dropped here

Much better!

How does it work?

When rustc's trait system determines that a trait wasn't implemented, in this case std::marker::Send, it emits this error. The trait system produces a chain of "obligations". Obligations are types which denote where a bound (e.g T: Send in is_send) originated, or where a bound was propagated.

To improve this diagnostic, the chain of obligations is now treated like a stack frame, where each "frame" of obligations represents each function's contribution to the error. Let's make that more concrete with a very rough approximation:

Obligation {
    kind: DerivedObligation(/* generator that captured `g` */),
    source: /* `Span` type pointing at `bar`'s location in user code */,
    parent: Some(Obligation {
        kind: DerivedObligation(/* generator calling `bar` */),
        source: /* `Span` type pointing at `foo`'s location in user code */,
        parent: Some(Obligation {
            kind: ItemObligation(/* type representing `std::marker::Send` */),
            source: /* `Span` type pointing at `is_send`'s location in user code */,
            cause: None,
        }),
    }),
}

The compiler matches against the chain expecting an ItemObligation and some DerivedObligations containing generators, which identifies the error we want to improve. Using information from these obligations, rustc can construct the specialized error shown above - if you'd like to see what the actual implementation looks like, check out PR #64895.

If you're interested in improving diagnostics like this, or even just fixing bugs, consider contributing to the compiler! There are many working groups to join and resources to help you get started (like the rustc dev guide or the compiler team documentation).

What's next?

More improvements to this diagnostic are planned and being worked on, so that it is applicable in more cases, and has specialized messages for Send and Sync, like below:

error[E0277]: future cannot be sent between threads safely
  --> src/main.rs:23:5
   |
5  | fn is_send<T: Send>(t: T) {
   |    -------    ---- required by this bound in `is_send`
...
23 |     is_send(foo());
   |     ^^^^^^^ future returned by `foo` is not `Send`
   |
   = help:  future is not `Send` as this value is used across an await
note: future does not implement `std::marker::Send` as this value is used across an await
  --> src/main.rs:15:3
   |
14 |   let g = x.lock().unwrap();
   |       - has type `std::sync::MutexGuard<'_, u32>`
15 |   baz().await;
   |   ^^^^^^^^^^^ await occurs here, with `g` maybe used later
16 | }
   | - `g` is later dropped here