List of mistakes you can make with unsafe

I think I said somewhere it would be helpful to have a list of mistakes you can easily accidentally make with unsafe, so I thought I would start one ( partially prompted by a mistake I made myself that I only just noticed today ).

I will be editing this post as I remember more mistakes I made..., or collecting contributions from others in the comments.

(1) Failing to add appropriate trait bounds when implementing an unsafe trait. For example

unsafe impl<'a, K, V, A: Tuning> Send for CursorMutKey<'a, K, V, A> {}

needs to be

unsafe impl<'a, K: Send, V: Send, A: Tuning + Send> Send for CursorMutKey<'a, K, V, A> {}

(2) Failing to allow for trait methods to panic, for example when implementing clone you have to allow for clone to panic, and not lose manually allocated memory (or worse, end up with uninitialized memory). I did this more than once! The solution can involve a struct that implements drop like this.

(3) The raw allocator API has undefined behavior if you pass in 0 for an allocation size.. Yup, I managed to hit this one.

(4) Creating aliased mutable references when trying to implement iteration in a naive way. I don't remember now exactly what I did, but Miri was not happy. Remember that you can use raw pointers to do things that are not valid for references. Generally be careful with the transition between raw pointers and references.

(5) Simply failing to deallocate manually allocated memory. Miri can detect this.

2 Likes

Co-mingling references and pointers.

Misaligned memory. For example, allocating a heap buffer as Vec<u8> then using that in an API call that returns a struct. (That's one of the reasons I made this.)

2 Likes

I can’t tell from just a cursory inspection of your code, but you may need to have some Sync bounds in there as well— If sending the CursorMutKey to another thread will let multiple threads concurrently access the same K, V, or A, they need to be bound on Send+Sync instead of just Send.


While this is generally a mistake, it’s worth noting that (unlike the others) it is still safe— You’ll have a memory leak, but your program won’t start randomly misbehaving. For that reason, it’s sometimes a viable option to leak memory if the alternative is UB. Of course, doing neither is the best option if you can arrange it.

I am going by the bounds in the std implementation, I presume they are correct, and I think copying them seems right.

( They are auto traits, but this still seems valid to me )

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.