Home > Back-end >  Surf dependency causes "cannot be shared between threads safely" error in previously compi
Surf dependency causes "cannot be shared between threads safely" error in previously compi

Time:02-14

I'm trying to write a chat bot that supports the matrix protocol, and I ran into this problem that I can't wrap my head around. On its own the code compiles without issue, but adding "surf" as a dependency to the Cargo.toml causes a "dyn log::kv::source::Source` cannot be shared between threads safely" error.

This is the minimal code for which this happens:

main.rs:

use std::convert::TryFrom;
use matrix_sdk::{
    Client, Result,
    ruma::{UserId},
};
use async_trait::async_trait;
    
async fn new_matrix_connector() -> Option<()> {
    let username = "NAME";
    let password = "PASSWORD";

    let alice = match UserId::try_from(username) {
        Ok(user) => user,
        Err(_) => {return None;}
    };
    let client = match Client::new_from_user_id(alice.clone()).await {
        Ok(client) => client,
        Err(_) => {return None;}
    };
    match client.login(alice.localpart(), password, None, None).await {
        Ok(_) => {},
        Err(_) => {return None;}
    }
    Some(())
}
    
#[async_trait]
trait Loader {
    async fn load(&self) -> Option<()>;
}
    
struct TestLoader {}
    
#[async_trait]
impl Loader for TestLoader {
    async fn load(&self) -> Option<()> {
        new_matrix_connector().await
    }
}
    
#[tokio::main]
async fn main() -> Result<()> {
    let loader = TestLoader{};
    let _res = loader.load();
    Ok(())
}

Cargo.toml:

[package]
name = "matrixtest"
version = "0.1.0"
edition = "2018"
        
[dependencies]
matrix-sdk = "0.4.1"
tokio = { version = "1", features = ["full"] }
async-trait = "0.1.52"
surf = "2.3.2"

These are the full errors caused:

error[E0277]: `dyn log::kv::source::Source` cannot be shared between threads safely
  --> src/main.rs:38:40
   |
38 |       async fn load(&self) -> Option<()> {
   |  ________________________________________^
39 | |         new_matrix_connector().await
40 | |     }
   | |_____^ `dyn log::kv::source::Source` cannot be shared between threads safely
   |
   = help: the trait `Sync` is not implemented for `dyn log::kv::source::Source`
   = note: required because of the requirements on the impl of `Send` for `&dyn log::kv::source::Source`
   = note: required because it appears within the type `log::KeyValues<'_>`
   = note: required because it appears within the type `log::Record<'_>`
   = note: required because it appears within the type `log::RecordBuilder<'_>`
   = note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10, 't11, 't12, 't13, 't14, 't15, 't16, 't17, 't18, 't19, 't20, 't21, 't22, 't23, 't24, 't25> {ResumeTy, log::Level, log::Metadata<'r>, &'s (dyn log::Log   't0), &'t1 mut log::RecordBuilder<'t2>, log::RecordBuilder<'t3>, &'t4 str, std::option::Option<&'t5 str>, u32, std::option::Option<u32>, [&'t6 str; 2], &'t7 [&'t8 str], &'t9 [&'t10 str; 2], &'t11 matrix_sdk::Client, impl for<'t12> std::future::Future, (), tracing_core::subscriber::Interest, &'t13 tracing_core::metadata::Metadata<'t14>, tracing_core::field::Iter, &'t15 tracing_core::field::FieldSet, &'t16 mut tracing_core::field::Iter, std::option::Option<tracing_core::field::Field>, tracing_core::field::Field, &'t17 tracing_core::field::Field, LoginInfo<'t18>, matrix_sdk::ruma::api::ruma_client_api::r0::session::login::Request<'t19>, std::option::Option<RequestConfig>, impl for<'t20, 't21> std::future::Future, matrix_sdk::ruma::api::ruma_client_api::r0::session::login::Response, matrix_sdk::Client, &'t22 matrix_sdk_base::client::BaseClient, matrix_sdk_base::client::BaseClient, &'t23 matrix_sdk::ruma::api::ruma_client_api::r0::session::login::Response, impl for<'t24, 't25> std::future::Future}`
   = note: required because it appears within the type `[static generator@matrix_sdk::Client::login::{closure#0}::{closure#0}]`
   = note: required because it appears within the type `from_generator::GenFuture<[static generator@matrix_sdk::Client::login::{closure#0}::{closure#0}]>`
   = note: required because it appears within the type `impl std::future::Future`
   = note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10> {ResumeTy, &'r matrix_sdk::Client, &'s str, std::option::Option<&'t0 str>, tracing::span::Span, impl for<'t1, 't2, 't3, 't4, 't5> std::future::Future, tracing::instrument::Instrumented<impl for<'t6, 't7, 't8, 't9, 't10> std::future::Future>, ()}`
   = note: required because it appears within the type `[static generator@matrix_sdk::Client::login::{closure#0}]`
   = note: required because it appears within the type `from_generator::GenFuture<[static generator@matrix_sdk::Client::login::{closure#0}]>`
   = 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, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6> {ResumeTy, &'r str, matrix_sdk::ruma::UserId, &'s matrix_sdk::ruma::UserId, impl std::future::Future, (), matrix_sdk::Client, &'t0 matrix_sdk::Client, std::option::Option<&'t1 str>, impl for<'t2, 't3, 't4, 't5, 't6> std::future::Future}`
   = note: required because it appears within the type `[static generator@src/main.rs:8:47: 27:2]`
   = note: required because it appears within the type `from_generator::GenFuture<[static generator@src/main.rs:8:47: 27:2]>`
   = 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> {ResumeTy, &'r TestLoader, impl std::future::Future, ()}`
   = note: required because it appears within the type `[static generator@src/main.rs:38:40: 40:6]`
   = note: required because it appears within the type `from_generator::GenFuture<[static generator@src/main.rs:38:40: 40:6]>`
   = note: required because it appears within the type `impl std::future::Future`
   = note: required for the cast to the object type `dyn std::future::Future<Output = std::option::Option<()>>   Send`

error[E0277]: `core::fmt::Opaque` cannot be shared between threads safely
  --> src/main.rs:38:40
   |
38 |       async fn load(&self) -> Option<()> {
   |  ________________________________________^
39 | |         new_matrix_connector().await
40 | |     }
   | |_____^ `core::fmt::Opaque` cannot be shared between threads safely
   |
   = help: within `[ArgumentV1<'_>]`, the trait `Sync` is not implemented for `core::fmt::Opaque`
   = note: required because it appears within the type `&core::fmt::Opaque`
   = note: required because it appears within the type `ArgumentV1<'_>`
   = note: required because it appears within the type `[ArgumentV1<'_>]`
   = note: required because of the requirements on the impl of `Send` for `&[ArgumentV1<'_>]`
   = note: required because it appears within the type `Arguments<'_>`
   = note: required because it appears within the type `log::Record<'_>`
   = note: required because it appears within the type `log::RecordBuilder<'_>`
   = note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10, 't11, 't12, 't13, 't14, 't15, 't16, 't17, 't18, 't19, 't20, 't21, 't22, 't23, 't24, 't25> {ResumeTy, log::Level, log::Metadata<'r>, &'s (dyn log::Log   't0), &'t1 mut log::RecordBuilder<'t2>, log::RecordBuilder<'t3>, &'t4 str, std::option::Option<&'t5 str>, u32, std::option::Option<u32>, [&'t6 str; 2], &'t7 [&'t8 str], &'t9 [&'t10 str; 2], &'t11 matrix_sdk::Client, impl for<'t12> std::future::Future, (), tracing_core::subscriber::Interest, &'t13 tracing_core::metadata::Metadata<'t14>, tracing_core::field::Iter, &'t15 tracing_core::field::FieldSet, &'t16 mut tracing_core::field::Iter, std::option::Option<tracing_core::field::Field>, tracing_core::field::Field, &'t17 tracing_core::field::Field, LoginInfo<'t18>, matrix_sdk::ruma::api::ruma_client_api::r0::session::login::Request<'t19>, std::option::Option<RequestConfig>, impl for<'t20, 't21> std::future::Future, matrix_sdk::ruma::api::ruma_client_api::r0::session::login::Response, matrix_sdk::Client, &'t22 matrix_sdk_base::client::BaseClient, matrix_sdk_base::client::BaseClient, &'t23 matrix_sdk::ruma::api::ruma_client_api::r0::session::login::Response, impl for<'t24, 't25> std::future::Future}`
   = note: required because it appears within the type `[static generator@matrix_sdk::Client::login::{closure#0}::{closure#0}]`
   = note: required because it appears within the type `from_generator::GenFuture<[static generator@matrix_sdk::Client::login::{closure#0}::{closure#0}]>`
   = note: required because it appears within the type `impl std::future::Future`
   = note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10> {ResumeTy, &'r matrix_sdk::Client, &'s str, std::option::Option<&'t0 str>, tracing::span::Span, impl for<'t1, 't2, 't3, 't4, 't5> std::future::Future, tracing::instrument::Instrumented<impl for<'t6, 't7, 't8, 't9, 't10> std::future::Future>, ()}`
   = note: required because it appears within the type `[static generator@matrix_sdk::Client::login::{closure#0}]`
   = note: required because it appears within the type `from_generator::GenFuture<[static generator@matrix_sdk::Client::login::{closure#0}]>`
   = 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, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6> {ResumeTy, &'r str, matrix_sdk::ruma::UserId, &'s matrix_sdk::ruma::UserId, impl std::future::Future, (), matrix_sdk::Client, &'t0 matrix_sdk::Client, std::option::Option<&'t1 str>, impl for<'t2, 't3, 't4, 't5, 't6> std::future::Future}`
   = note: required because it appears within the type `[static generator@src/main.rs:8:47: 27:2]`
   = note: required because it appears within the type `from_generator::GenFuture<[static generator@src/main.rs:8:47: 27:2]>`
   = 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> {ResumeTy, &'r TestLoader, impl std::future::Future, ()}`
   = note: required because it appears within the type `[static generator@src/main.rs:38:40: 40:6]`
   = note: required because it appears within the type `from_generator::GenFuture<[static generator@src/main.rs:38:40: 40:6]>`
   = note: required because it appears within the type `impl std::future::Future`
   = note: required for the cast to the object type `dyn std::future::Future<Output = std::option::Option<()>>   Send`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `matrix` due to 2 previous errors

Without the surf dependency this compiles without issue. It also doesn't happen if the load() function is implemented for the TestLoader struct directly.

CodePudding user response:

A friend of mine figured out what the problem was:

The problem wasn't surf directly, but the tracing crate with the log feature enabled, on which surf indirectly depends. There is already an issue on github on it, but it's not yet resolved.

The problem gets triggered by matrix-sdk because it also uses tracing, but usually without the log feature. The line that triggers it is this:

info!("Registering to {}", self.homeserver().await);

Changing it to

let homeserver = self.homeserver().await;
info!("Registering to {}", homeserver);

resolves the issue. A fix to this exists in a fork of matrix-sdk (fixed in this commit), but as far as I can tell it hasn't been merged as of yet. There was also no release since then (most recent version is 0.4.1), so maybe it'll get fixed for the next release.

For the time being my workaround for this problem is to not depend on surf.

  • Related