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

[Merged by Bors] - Fix double drop in BlobVec::replace_unchecked (#2597) #2848

Closed
wants to merge 2 commits into from

Conversation

sapir
Copy link
Contributor

@sapir sapir commented Sep 20, 2021

Objective

I thought I'd have a go a trying to fix #2597.

Hopefully fixes #2597.

Solution

I reused the memory pointed to by the value parameter, that is already required by insert to not be dropped, to contain the extracted value while dropping it.

@github-actions github-actions bot added the S-Needs-Triage This issue needs to be labelled label Sep 20, 2021
@sapir sapir force-pushed the fix-blob-vec-double-drop branch 3 times, most recently from 8221c7f to 49b4071 Compare September 21, 2021 22:27
@alice-i-cecile alice-i-cecile added A-ECS Entities, components, systems, and events C-Bug An unexpected or incorrect behavior S-Needs-Review and removed S-Needs-Triage This issue needs to be labelled labels Sep 22, 2021
@alice-i-cecile
Copy link
Member

Thanks! Is there a way to write a test for this?

@sapir
Copy link
Contributor Author

sapir commented Sep 23, 2021

Thanks! Is there a way to write a test for this?

I'll try to adapt the code snippet from the issue.

@sapir
Copy link
Contributor Author

sapir commented Sep 23, 2021

As it turns out, the test failed :) So I fixed another bug.

I also have a test for the second code snippet from the issue (#2597 (comment)) but it's still failing, I think due to Table::allocate increasing the column length before the data is actually written. Fixing that seems more complicated, so I'll just leave that test out and open a separate issue for it.

@alice-i-cecile
Copy link
Member

Awesome, thanks for the test and the issue :)

@alice-i-cecile alice-i-cecile added the P-High This is particularly urgent, and deserves immediate attention label Oct 10, 2021
@@ -97,12 +98,18 @@ impl BlobVec {

/// # Safety
/// - index must be in-bounds
// - memory must be previously initialized
/// - memory must be previously initialized
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what memory? this should be clearer that we're talking about value (and also what type is supposed to be initialised behind it)

Copy link
Contributor Author

@sapir sapir Oct 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it to say value but after seeing the same comment at initialize_unchecked I'm pretty sure this is referring to the memory at index/ptr, so I'll change it to say that

edit: I don't think I phrased it very clearly, though

Comment on lines 102 to 103
/// - the contents of `*value` must not be dropped by the caller. (In fact,
/// this function may overwrite them.)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// - the contents of `*value` must not be dropped by the caller. (In fact,
/// this function may overwrite them.)
/// - the contents of `*value` is left logically uninitialised/moved out of and as such
/// should not be used or dropped by the caller

@@ -88,6 +88,7 @@ impl BlobVec {
/// # Safety
/// - index must be in bounds
/// - memory must be reserved and uninitialized
/// - the contents of `*value` must not be dropped by the caller
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont see why this is the case. this function does not drop the data that was written into value so if we aren't dropping the data behind value somewhere this would leak memory

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*value is moved into the BlobVec, so if the caller drops it, that would cause a double drop when dropping the BlobVec or moving the value out again.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh right this is copy not swap like the other function 🤦‍♀️

// calling `drop`. Otherwise, if `drop` panics, then when the collection
// is dropped during stack unwinding, the collection's `Drop` impl will
// call `drop` again for the old value, so we get a double drop.
std::ptr::swap_nonoverlapping(value, ptr, self.item_layout.size());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be cheaper to set self.len to 0 before dropping and then set it back afterwards rather than using swap_nonoverlapping

Copy link
Member

@DJMcNab DJMcNab left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These seem correct - I'm not quite sure that the safety comments are quite as precise as I'd choose to make them, but these are strict improvements.

@alice-i-cecile alice-i-cecile added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review labels Oct 10, 2021
@sapir sapir force-pushed the fix-blob-vec-double-drop branch 2 times, most recently from 8ad92f9 to 1337eb1 Compare October 14, 2021 23:52
@alice-i-cecile alice-i-cecile removed the S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it label Oct 15, 2021
@alice-i-cecile alice-i-cecile added this to the Bevy 0.6 milestone Oct 15, 2021
Copy link
Member

@BoxyUwU BoxyUwU left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic looks correct to me, the safety comments could be better but that's not the point of this PR and they're already an improvement.

@alice-i-cecile alice-i-cecile added the S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it label Oct 15, 2021
@@ -109,8 +109,8 @@ macro_rules! tuple_impl {
#[allow(non_snake_case)]
let ($(mut $name,)*) = self;
$(
func((&mut $name as *mut $name).cast::<u8>());
std::mem::forget($name);
let mut value = ::std::mem::ManuallyDrop::new($name);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ManuallyDrop isn't strong enough here - you need to use MaybeUninit. For example, see ea5e315

I'm happy to move this change into #2975

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok I removed this commit

@sapir sapir force-pushed the fix-blob-vec-double-drop branch from 1337eb1 to 9a8ff08 Compare October 16, 2021 18:53
@sapir sapir force-pushed the fix-blob-vec-double-drop branch from 9a8ff08 to b499744 Compare October 16, 2021 20:50
@cart
Copy link
Member

cart commented Dec 18, 2021

looks good to me. thanks!

@cart
Copy link
Member

cart commented Dec 18, 2021

bors r+

bors bot pushed a commit that referenced this pull request Dec 18, 2021
# Objective

I thought I'd have a go a trying to fix #2597.

Hopefully fixes #2597.

## Solution

I reused the memory pointed to by the value parameter, that is already required by `insert` to not be dropped, to contain the extracted value while dropping it.
@bors bors bot changed the title Fix double drop in BlobVec::replace_unchecked (#2597) [Merged by Bors] - Fix double drop in BlobVec::replace_unchecked (#2597) Dec 18, 2021
@bors bors bot closed this Dec 18, 2021
@sapir sapir deleted the fix-blob-vec-double-drop branch December 18, 2021 21:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ECS Entities, components, systems, and events C-Bug An unexpected or incorrect behavior P-High This is particularly urgent, and deserves immediate attention S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Drop called multiple times if drop panics.
6 participants