Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Force structures to be Copy instead of Clone #2

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Kerollmops
Copy link

@Kerollmops Kerollmops commented Feb 10, 2019

I fixed a bug related to unsafe code inside the RdxSort::rdxsort slice implementation where you used the unsafe copy_nonoverlapping function on Clone restricted types, which is not enough to be safe.

rdxsort-rs/src/sort.rs

Lines 83 to 87 in c654971

unsafe {
ptr::copy_nonoverlapping(bucket.as_ptr(),
self.get_unchecked_mut(pos),
bucket.len());
}

As the function documentation warns us:

If T is not Copy, using both the values in the region beginning at *src and the region beginning at *dst can violate memory safety.

As a good example we can just take reference counted types that must increment a counter when cloned and decrement it when dropped, in this case you just use memcpy internally on the Rc structure that does not inform the type that it has been cloned but before that you used iter().cloned() on these same structs.

helper_bucket(&mut buckets_a, self.iter().cloned(), cfg_nbuckets, 0);

It is not safe because it could generate use-after-free bugs, the Rc is previously cloned, incrementing the internal counter, copied without incrementing it (the pointer to the data is copied without being tracked by the counter) and dropped so decrementing the counter which can trigger the drop function, the memory area where the copy has been made can contain pointers to freed data.

So solutions to fix this bug could be either:

  • to restrict the T type to be Copy therefore this function call can be considered "safe"
  • to use another unsafe call to forget some buckets elements (Vec::set_len)

@TimNN
Copy link

TimNN commented Mar 27, 2019

Requiring Copy is certainly the easier fix, but I think that a proper fix:

  • Must not intermix .cloned() with copy_nonoverlapping() (e.g. use .map(|i| read_ptr(i)) (or something) instead)
  • Make sure that only one of the copied elements is ever observed (even in edge cases like drop-on-panic or special cases like assigning to / overwriting variables / slice elements).

@mtak-
Copy link

mtak- commented Mar 27, 2019

For Rc this code would actually work, since all the Rcs are always cloned and dropped in equal amounts. String/Box etc, would be broken.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants