From 00bd306e0d060fc737d670e9aacd2789d3103785 Mon Sep 17 00:00:00 2001 From: William Brown Date: Wed, 19 Dec 2018 11:32:56 +1000 Subject: [PATCH 1/3] Extend documentation for mem uninit to discuss partial allocation of the values --- src/libcore/mem.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index afd9fcb1fba84..7e4e83999c1a3 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -530,6 +530,12 @@ pub unsafe fn zeroed() -> T { /// it goes out of scope (and therefore would be dropped). Note that this /// includes a `panic` occurring and unwinding the stack suddenly. /// +/// If you partially initialize an array, you may need to use +/// [`ptr::drop_in_place`][drop_in_place] to remove the set you have created +/// followed by [`mem::forget`][mem_forget] to prevent drop running on the +/// array. If a partially allocated array is dropped this may lead to +/// undefined behaviour. +/// /// # Examples /// /// Here's how to safely initialize an array of [`Vec`]s. @@ -583,11 +589,47 @@ pub unsafe fn zeroed() -> T { /// println!("{:?}", &data[0]); /// ``` /// +/// This example shows how to handle partially allocated arrays, which could +/// be found in low-level datastructures. +/// +/// ``` +/// use std::mem; +/// use std::ptr; +/// +/// // Count the number of elements we have assigned. +/// let mut data_len: usize = 0; +/// let mut data: [String; 1000]; +/// +/// unsafe { +/// data = mem::uninitialized(); +/// +/// for elem in &mut data[0..500] { +/// ptr::write(elem, String::from("hello")); +/// data_len += 1; +/// } +/// +/// // For each item in the array, drop if we allocated it. +/// for i in &mut data[0..data_len] { +/// ptr::drop_in_place(i); +/// } +/// } +/// // Forget the data. If this is allowed to drop, you may see a crash such as: +/// // 'mem_uninit_test(2457,0x7fffb55dd380) malloc: *** error for object 0x7ff3b8402920: pointer being freed was not allocated' +/// mem::forget(data); +/// ``` +/// +/// An alternate strategy is to use [`mem::zeroed`][mem_zeroed] with ptr +/// comparison. This is a very error prone strategy and may only be relevant +/// for FFI. +/// /// [`Vec`]: ../../std/vec/struct.Vec.html /// [`vec!`]: ../../std/macro.vec.html /// [`Clone`]: ../../std/clone/trait.Clone.html /// [ub]: ../../reference/behavior-considered-undefined.html /// [write]: ../ptr/fn.write.html +/// [drop_in_place]: ../ptr/fn.drop_in_place.html +/// [mem_zeroed]: fn.zeroed.html +/// [mem_forget]: fn.forget.html /// [copy]: ../intrinsics/fn.copy.html /// [copy_no]: ../intrinsics/fn.copy_nonoverlapping.html /// [`Drop`]: ../ops/trait.Drop.html From 0829d0c0e480a3729dcfe4f28f5969277dc8f646 Mon Sep 17 00:00:00 2001 From: William Brown Date: Wed, 19 Dec 2018 12:40:57 +1000 Subject: [PATCH 2/3] Updates based on comment --- src/libcore/mem.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 7e4e83999c1a3..7492cf4c5ed32 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -531,9 +531,9 @@ pub unsafe fn zeroed() -> T { /// includes a `panic` occurring and unwinding the stack suddenly. /// /// If you partially initialize an array, you may need to use -/// [`ptr::drop_in_place`][drop_in_place] to remove the set you have created -/// followed by [`mem::forget`][mem_forget] to prevent drop running on the -/// array. If a partially allocated array is dropped this may lead to +/// [`ptr::drop_in_place`][drop_in_place] to remove the elements you have fully +/// initialized followed by [`mem::forget`][mem_forget] to prevent drop running +/// on the array. If a partially allocated array is dropped this will lead to /// undefined behaviour. /// /// # Examples @@ -589,7 +589,7 @@ pub unsafe fn zeroed() -> T { /// println!("{:?}", &data[0]); /// ``` /// -/// This example shows how to handle partially allocated arrays, which could +/// This example shows how to handle partially initialized arrays, which could /// be found in low-level datastructures. /// /// ``` @@ -618,10 +618,6 @@ pub unsafe fn zeroed() -> T { /// mem::forget(data); /// ``` /// -/// An alternate strategy is to use [`mem::zeroed`][mem_zeroed] with ptr -/// comparison. This is a very error prone strategy and may only be relevant -/// for FFI. -/// /// [`Vec`]: ../../std/vec/struct.Vec.html /// [`vec!`]: ../../std/macro.vec.html /// [`Clone`]: ../../std/clone/trait.Clone.html From b2d8040e6f89318c0ca7f5512ca31f8311b14a36 Mon Sep 17 00:00:00 2001 From: William Brown Date: Wed, 19 Dec 2018 19:09:54 +1000 Subject: [PATCH 3/3] Fix tidy error --- src/libcore/mem.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 7492cf4c5ed32..9d1f5ce403570 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -614,7 +614,8 @@ pub unsafe fn zeroed() -> T { /// } /// } /// // Forget the data. If this is allowed to drop, you may see a crash such as: -/// // 'mem_uninit_test(2457,0x7fffb55dd380) malloc: *** error for object 0x7ff3b8402920: pointer being freed was not allocated' +/// // 'mem_uninit_test(2457,0x7fffb55dd380) malloc: *** error for object +/// // 0x7ff3b8402920: pointer being freed was not allocated' /// mem::forget(data); /// ``` ///