actix-web: InternalError can trigger memory unsafety (such as use-after-free or double-free)

There is an unsafe impl Send<T> for InternalError<T>, making it so one can construct an InternalError with any type, and accidentally send it to another thread. However, the implementation of InternalError isn’t actually safe to implement Send for any T.

Consider this example:

let my_err = Rc::new("foobar".to_owned());
let int_err = InternalError::new(my_err.clone(), StatusCode::BAD_REQUEST);
thread::spawn(move || {
    let _moved = int_err;
    // clone 1 dropped
})
let my_err2 = my_err.clone();
// clone 2 dropped
// orig dropped

The drop of the InternalError in the other thread can cause the ref count to race with the clone in the first thread. It’s now possible that the 2nd drop (out of 3) will free the allocation. Using the 3rd (the original) afterwards would cause use-after-free bugs. Finally dropping it would cause a double-free.

Seems related to #289

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 4
  • Comments: 15 (10 by maintainers)

Commits related to this issue

Most upvoted comments

I’m just reporting a memory unsafety bug I noticed that can be triggered in safe Rust (safe from a user’s perspective). I didn’t see an issue mentioning it, so I thought I’d bring it up in case it was missed!

@seanmonstar do you think I don’t understand impl Send? 😃

If not another ticket, shouldn’t this issue be re-opened for now? It would be good to have an open record, especially if anyone else comes across it and has an idea for the fix.

@anderejd Please see #289

FWIW, the problem doesn’t exist because of failure. It’s the unsafe impl of Send and Sync. If those impls were removed, then just the default ones would exist, which are safe.

This is absolutely conscious decision.