cr0sh / threadalone

Make any value Send + Sync but only available on its original thread. Don't use on multi-threaded environments!

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Unsound sending of non-Send types

dtolnay opened this issue · comments

Continued from rustsec/advisory-db#1846.

Repro of data race causing segfault in safe code:

use std::cell::Cell;
use std::thread;
use threadalone::ThreadAlone;

struct Corrupt<'a>(&'a Cell<String>);

impl<'a> Drop for Corrupt<'a> {
    fn drop(&mut self) {
        self.0.set(".".repeat(40));
    }
}

fn main() {
    let cell = Cell::new(String::new());
    thread::scope(|s| loop {
        let bad = ThreadAlone::new(Corrupt(&cell));
        s.spawn(|| drop(bad));
        cell.set(String::new());
    });
}
$ cargo build && target/debug/testing >&2 2>/dev/full
Segmentation fault (core dumped)

This is the Drop impl in question:

threadalone/src/lib.rs

Lines 161 to 166 in 457fd19

fn drop(self: Pin<&mut Self>) {
if thread::current().id() != self.thread_id {
eprintln!("called Drop on another thread");
std::process::abort();
}
}

The intended behavior of this Drop impl was:

  • If correct thread, then drop T
  • If incorrect thread, then print and abort

whereas the actual behavior implemented in the above code is:

  • If correct thread, then drop T
  • If incorrect thread and stderr is writeable, then print and abort
  • If incorrect thread and stderr is not writeable, then drop T and unwind

See https://doc.rust-lang.org/1.75.0/std/macro.eprintln.html where it calls out that eprintln can panic.

A non-panicking eprintln would look like _ = writeln!(io::stderr(), ...).

Oh wow, nice catch. Will publish a fix later today. If you prefer, you can commit and submit a PR then I'll merge it. (Or I'll do on my own and leave a credit)

Actually I didn't consider that eprintln can even fail 😂 In macOS there's no /dev/full so didn't understand your intent at first glance

Hey @cr0sh, is a fixed version coming soon?

I see you have yanked affected versions already, would you be OK with me merging rustsec/advisory-db#1846 before a fix is published?

@ShnatselI I published 0.2.1 which resolves the request. I'm not familiar of the process about rustsec, but I think you can merge the PR.
@dtolnay I did with myself and leaved a credit on ec42d1a. Thanks again!