Skip to content

Thread-safety in a mixed Rust/C++ code base #73

Description

@aapoalas

Rust and C++ have very different views on how thread-safety works and how it is documented: a C++ method may be thread-safe or -unsafe independent of its const-ness, and it all basically depends on just documentation. In Rust the information is in the type system with Send and Sync.

In a world where C++ class instances are regularly passed into Rust, it falls upon the Rust bindings to divine whether that object can be sent to a foreign thread (Send), and which of its methods are Sync. It is also not necessarily clear if thread-safe methods can be expressed in Rust as taking &self depending on the field declarations:

class Foo {
  Mutex mutex_;
  // static_ is here to make it impossible for Rust to declare a data_: CppMuted<*mut c_void>
  uint32_t static_;
  void *data_;

  void thread_safe_set(void *data) {
    auto guard = mutex_.lock();
    data_ = data;
  }
}
struct Foo {
  mutex_: CppMutex,
  static_: u32,
  data_: *mut c_void,
}

extern "C" {
  fn lib__Foo__thread_safe_set(this: *mut Foo, data: *mut c_void);
}

impl Foo {
  #[inline(always)]
  fn thread_safe_set(&self, data: *mut c_void) {
    unsafe { lib__Foo__thread_safe_set(ptr::from_ref(self).const_cast(), data) }
  }
}

The &self here promises to Rust that both static_ and data_ stay unchanged, but the FFI call actually mutates data_: on the Rust side we should be wrapping data_ in an SyncUnsafeCell but that is generally impossible to figure out from just the header declarations.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    l-rustChanges that are mainly in Rustp-safetySafety or soundness related problems or use casesp-semanticsLanguage semantics differencessolved-crubitSolved by Crubitt-problem-statementA description of an interop problem

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions