Skip to content

RingBuffer allows sending Non-Send types across threads #1

@Qwaz

Description

@Qwaz

Hello fellow Rustacean,
we (Rust group @sslab-gatech) are scanning Rust code on crates.io for potential memory safety and soundness bugs and found an issue in this crate which allows safe Rust code to exhibit an undefined behavior.

Issue Description

unsafe impl<T> Send for RingBuffer<T> {}
unsafe impl<T> Sync for RingBuffer<T> {}

RingBuffer implements Send/Sync regardless of whether the internal type implements Send/Sync. This allows users to send a non-Send type across threads with RingBuffer.

RingBuffer's Send/Sync should probably have a trait bound on the internal type T, or if RingBuffer needs to implement Send/Sync and it is not meant to be created by the end user, new() should be hidden with pub(crate) or so.

Reproduction

Below is an example program that sends Non-Send type across threads using safe APIs of disrustor.

Show Detail

This example just shows that non-Send type is sent across the thread, but it is possible to demonstrate a data race with a more complicated example.

#![forbid(unsafe_code)]

#[macro_use]
extern crate static_assertions;

use disrustor::internal::RingBuffer;

use std::marker::PhantomData;
use std::thread;

struct NonSend {
    created_thread: thread::ThreadId,
    // Mark this struct as `NonSend`
    _marker: PhantomData<*mut ()>,
}

assert_not_impl_all!(NonSend: Send);

impl Default for NonSend {
    fn default() -> Self {
        NonSend {
            created_thread: thread::current().id(),
            _marker: PhantomData,
        }
    }
}

impl Drop for NonSend {
    fn drop(&mut self) {
        if thread::current().id() != self.created_thread {
            panic!("NonSend destructor is running on a wrong thread!");
        }
    }
}

fn main() {
    let buffer = RingBuffer::<NonSend>::new(1);

    let handle = thread::spawn(move || {
        drop(buffer);
    });

    handle.join().unwrap();
}

Output:

thread '<unnamed>' panicked at 'NonSend destructor is running on a wrong thread!', src/main.rs:47:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Any', src/main.rs:59:19

Return code 101

Tested Environment

  • Crate: disrustor
  • Version: 0.2.0
  • OS: Ubuntu 20.04.1 LTS
  • Rustc version: rustc 1.48.0 (7eac88abb 2020-11-16)
  • 3rd party dependencies:
    • static_assertions = { version = "1.1.0" }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions