logoalt Hacker News

tekacstoday at 6:04 PM4 repliesview on HN

To pre-empt the folks who'll come in here and laugh about how Rust should be preventing memory corruption... I'll just directly quote from the mailing list:

  Rust Binder contains the following unsafe operation:
  
   // SAFETY: A `NodeDeath` is never inserted into the death list
   // of any node other than its owner, so it is either in this
   // death list or in no death list.
   unsafe { node_inner.death_list.remove(self) };
  
  This operation is unsafe because when touching the prev/next pointers of
  a list element, we have to ensure that no other thread is also touching
  them in parallel. If the node is present in the list that `remove` is
  called on, then that is fine because we have exclusive access to that
  list. If the node is not in any list, then it's also ok. But if it's
  present in a different list that may be accessed in parallel, then that
  may be a data race on the prev/next pointers.
  
  And unfortunately that is exactly what is happening here. In
  Node::release, we:
  
   1. Take the lock.
   2. Move all items to a local list on the stack.
   3. Drop the lock.
   4. Iterate the local list on the stack.
  
  Combined with threads using the unsafe remove method on the original
  list, this leads to memory corruption of the prev/next pointers. This
  leads to crashes like this one:

Replies

torginustoday at 8:47 PM

Sorry, but this is like saying 'when I am not wrong, I am right 100% of the time'.

The devs didn't write unsafe Rust to experience the thrills of living dangerously, they wrote it because the primitives were impossible to express in safe Rust.

If I were to write a program in C++ that has a thread-safe doubly linked list in it, I'd be able to bet on that linked list will have safety bugs, not because C++ is an unsafe language, but because multi-threading is hard. In fact, I believe most memory safety errors today occur in the presence of multi-threading.

Rust doesn't offer me any way of making sure my code is safe in this case, I have to do the due diligence of trying my best and still accept that bugs might happen because this is a hard problem.

The difference between Rust and C++ in this case, is that the bad parts of Rust are cordoned off with glowing red lines, while the bad parts of C++ are not.

This might help me in minimizing the attack surface in the future, but I suspect Rust's practical benefits will end up less impactful than advertised, even when the language is full realized and at its best, because most memory safety issues occur in code that cannot be expressed in safe Rust and doing it in a safe Rust way is not feasible for some technical reason.

themafiatoday at 6:44 PM

So the prediction that incautious and unverified unsafe {} blocks would cause CVEs seems entirely accurate.

show 4 replies
Phelinofisttoday at 6:43 PM

I know nothing about Rust. But why is unsafe needed? Kinda sounds a lock would make this safe?

show 1 reply
samdoesnothingtoday at 6:38 PM

If rust is so inflexible that it requires the use of unsafe to solve problems, that's still rust's fault. You have to consider both safe rust behaviour as well as necessary unsafe code.

show 5 replies