Permalink
Please
sign in to comment.
Browse files
Fix incorrect unsafe in drop
The use of `epoch::unprotected` in the various `Drop` implementations rely on the fact that no method ever gives out a reference that outlives `&self`. If they did, then even though we have a `&mut self` there may still be live references to stuff stored in the map. It turns out not all returned references were tied to the lifetime of `&self`, allowing someone to write code like the following: ```rust let guard = epoch::pin(); map.insert(42, thingy, &guard); let thingy_ref = map.values().next().unwrap(); drop(map); // can now continue to use thingy_ref! ``` Notice here that `map` is dropped, at which point it will assume it owns _everything_ in the map. It creates an `epoch::unprotected` which _immediately_ runs any `defer_destroy` destructors. That means it will drop `thingy`. But since `thingy_ref` is not tied to the lifetime of `map` (just the lifetime of the `Guard`), it still lives, and we have a dangling pointer! There are two possible solutions to this. One is to make the `drop` implementations use `epoch::pin` rather than `epoch::unprotected`. This would allow all returned values to just be tied to the lifetime of their guards, but would also mean that even when you drop a map, the memory is not reclaimed. The other, which is what this PR does, is to tie every returned reference to the joint lifetime of the guard _and_ `&self`. That way, by the time we get to `Drop`, the `&mut self` tells us that there are indeed no references outstanding into `self`, and dropping anything in there immediately is fine.
- Loading branch information
0 comments on commit
a9c6890