Skip to content

Commit 5ae5dbd

Browse files
committed
Switch drop-flag to u8 to allow special tags to instrument state.
Refactored code so that the drop-flag values for initialized (`DTOR_NEEDED`) versus dropped (`DTOR_DONE`) are given explicit names. Add `mem::dropped()` (which with `DTOR_DONE == 0` is semantically the same as `mem::zeroed`, but the point is that it abstracts away from the particular choice of value for `DTOR_DONE`). Filling-drop needs to use something other than `ptr::read_and_zero`, so I added such a function: `ptr::read_and_drop`. But, libraries should not use it if they can otherwise avoid it. Fixes to tests to accommodate filling-drop.
1 parent d5408f3 commit 5ae5dbd

File tree

19 files changed

+258
-58
lines changed

19 files changed

+258
-58
lines changed

src/liballoc/arc.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,8 @@ impl<T: Sync + Send> Drop for Arc<T> {
329329
// This structure has #[unsafe_no_drop_flag], so this drop glue may run more than once (but
330330
// it is guaranteed to be zeroed after the first if it's run more than once)
331331
let ptr = *self._ptr;
332-
if ptr.is_null() { return }
332+
// if ptr.is_null() { return }
333+
if ptr.is_null() || ptr as usize == mem::POST_DROP_USIZE { return }
333334

334335
// Because `fetch_sub` is already atomic, we do not need to synchronize with other threads
335336
// unless we are going to delete the object. This same logic applies to the below
@@ -460,7 +461,7 @@ impl<T: Sync + Send> Drop for Weak<T> {
460461
let ptr = *self._ptr;
461462

462463
// see comments above for why this check is here
463-
if ptr.is_null() { return }
464+
if ptr.is_null() || ptr as usize == mem::POST_DROP_USIZE { return }
464465

465466
// If we find out that we were the last weak pointer, then its time to deallocate the data
466467
// entirely. See the discussion in Arc::drop() about the memory orderings

src/liballoc/rc.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ use core::default::Default;
154154
use core::fmt;
155155
use core::hash::{Hasher, Hash};
156156
use core::marker;
157-
use core::mem::{min_align_of, size_of, forget};
157+
use core::mem::{self, min_align_of, size_of, forget};
158158
use core::nonzero::NonZero;
159159
use core::ops::{Deref, Drop};
160160
use core::option::Option;
@@ -391,7 +391,7 @@ impl<T> Drop for Rc<T> {
391391
fn drop(&mut self) {
392392
unsafe {
393393
let ptr = *self._ptr;
394-
if !ptr.is_null() {
394+
if !ptr.is_null() && ptr as usize != mem::POST_DROP_USIZE {
395395
self.dec_strong();
396396
if self.strong() == 0 {
397397
ptr::read(&**self); // destroy the contained object
@@ -697,7 +697,7 @@ impl<T> Drop for Weak<T> {
697697
fn drop(&mut self) {
698698
unsafe {
699699
let ptr = *self._ptr;
700-
if !ptr.is_null() {
700+
if !ptr.is_null() && ptr as usize != mem::POST_DROP_USIZE {
701701
self.dec_weak();
702702
// the weak count starts at 1, and will only go to zero if all the strong pointers
703703
// have disappeared.

src/libcollections/btree/node.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,9 +280,11 @@ impl<T> Drop for RawItems<T> {
280280
#[unsafe_destructor]
281281
impl<K, V> Drop for Node<K, V> {
282282
fn drop(&mut self) {
283-
if self.keys.is_null() {
283+
if self.keys.is_null() ||
284+
(unsafe { self.keys.get() as *const K as usize == mem::POST_DROP_USIZE })
285+
{
284286
// Since we have #[unsafe_no_drop_flag], we have to watch
285-
// out for a null value being stored in self.keys. (Using
287+
// out for the sentinel value being stored in self.keys. (Using
286288
// null is technically a violation of the `Unique`
287289
// requirements, though.)
288290
return;

src/libcollections/vec.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1588,7 +1588,7 @@ impl<T> Drop for Vec<T> {
15881588
fn drop(&mut self) {
15891589
// This is (and should always remain) a no-op if the fields are
15901590
// zeroed (when moving out, because of #[unsafe_no_drop_flag]).
1591-
if self.cap != 0 {
1591+
if self.cap != 0 && self.cap != mem::POST_DROP_USIZE {
15921592
unsafe {
15931593
for x in &*self {
15941594
ptr::read(x);
@@ -1831,7 +1831,7 @@ impl<'a, T> ExactSizeIterator for Drain<'a, T> {}
18311831
#[stable(feature = "rust1", since = "1.0.0")]
18321832
impl<'a, T> Drop for Drain<'a, T> {
18331833
fn drop(&mut self) {
1834-
// self.ptr == self.end == null if drop has already been called,
1834+
// self.ptr == self.end == mem::POST_DROP_USIZE if drop has already been called,
18351835
// so we can use #[unsafe_no_drop_flag].
18361836

18371837
// destroy the remaining elements

src/libcore/intrinsics.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,13 +187,35 @@ extern "rust-intrinsic" {
187187
/// crate it is invoked in.
188188
pub fn type_id<T: ?Sized + 'static>() -> u64;
189189

190+
/// Create a value initialized to so that its drop flag,
191+
/// if any, says that it has been dropped.
192+
///
193+
/// `init_dropped` is unsafe because it returns a datum with all
194+
/// of its bytes set to the drop flag, which generally does not
195+
/// correspond to a valid value.
196+
///
197+
/// This intrinsic is likely to be deprecated in the future when
198+
/// Rust moves to non-zeroing dynamic drop (and thus removes the
199+
/// embedded drop flags that are being established by this
200+
/// intrinsic).
201+
#[cfg(not(stage0))]
202+
pub fn init_dropped<T>() -> T;
203+
190204
/// Create a value initialized to zero.
191205
///
192206
/// `init` is unsafe because it returns a zeroed-out datum,
193-
/// which is unsafe unless T is Copy.
207+
/// which is unsafe unless T is `Copy`. Also, even if T is
208+
/// `Copy`, an all-zero value may not correspond to any legitimate
209+
/// state for the type in question.
194210
pub fn init<T>() -> T;
195211

196212
/// Create an uninitialized value.
213+
///
214+
/// `uninit` is unsafe because there is no guarantee of what its
215+
/// contents are. In particular its drop-flag may be set to any
216+
/// state, which means it may claim either dropped or
217+
/// undropped. In the general case one must use `ptr::write` to
218+
/// initialize memory previous set to the result of `uninit`.
197219
pub fn uninit<T>() -> T;
198220

199221
/// Move a value out of scope without running drop glue.

src/libcore/mem.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,29 @@ pub unsafe fn zeroed<T>() -> T {
158158
intrinsics::init()
159159
}
160160

161+
/// Create a value initialized to an unspecified series of bytes.
162+
///
163+
/// The byte sequence usually indicates that the value at the memory
164+
/// in question has been dropped. Thus, *if* T carries a drop flag,
165+
/// any associated destructor will not be run when the value falls out
166+
/// of scope.
167+
///
168+
/// Some code at one time used the `zeroed` function above to
169+
/// accomplish this goal.
170+
///
171+
/// This function is expected to be deprecated with the transition
172+
/// to non-zeroing drop.
173+
#[inline]
174+
#[unstable(feature = "filling_drop")]
175+
pub unsafe fn dropped<T>() -> T {
176+
let mut x: T = uninitialized();
177+
let p: *mut u8 = transmute(&mut x as *mut T);
178+
for i in 0..size_of::<T>() {
179+
*p.offset(i as isize) = POST_DROP_U8;
180+
}
181+
x
182+
}
183+
161184
/// Create an uninitialized value.
162185
///
163186
/// Care must be taken when using this function, if the type `T` has a destructor and the value
@@ -291,6 +314,40 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T {
291314
#[stable(feature = "rust1", since = "1.0.0")]
292315
pub fn drop<T>(_x: T) { }
293316

317+
macro_rules! repeat_u8_as_u32 {
318+
($name:expr) => { (($name as u32) << 24 |
319+
($name as u32) << 16 |
320+
($name as u32) << 8 |
321+
($name as u32)) }
322+
}
323+
macro_rules! repeat_u8_as_u64 {
324+
($name:expr) => { ((repeat_u8_as_u32!($name) as u64) << 32 |
325+
(repeat_u8_as_u32!($name) as u64)) }
326+
}
327+
328+
// NOTE: Keep synchronized with values used in librustc_trans::trans::adt.
329+
//
330+
// In particular, the POST_DROP_U8 marker must never equal the
331+
// DTOR_NEEDED_U8 marker.
332+
//
333+
// For a while pnkfelix was using 0xc1 here.
334+
// But having the sign bit set is a pain, so 0x1d is probably better.
335+
//
336+
// And of course, 0x00 brings back the old world of zero'ing on drop.
337+
#[cfg(not(stage0))] pub const POST_DROP_U8: u8 = 0x0;
338+
#[cfg(not(stage0))] pub const POST_DROP_U32: u32 = repeat_u8_as_u32!(POST_DROP_U8);
339+
#[cfg(not(stage0))] pub const POST_DROP_U64: u64 = repeat_u8_as_u64!(POST_DROP_U8);
340+
341+
#[cfg(target_pointer_width = "32")]
342+
#[cfg(not(stage0))] pub const POST_DROP_USIZE: usize = POST_DROP_U32 as usize;
343+
#[cfg(target_pointer_width = "64")]
344+
#[cfg(not(stage0))] pub const POST_DROP_USIZE: usize = POST_DROP_U64 as usize;
345+
346+
#[cfg(stage0)] pub const POST_DROP_U8: u8 = 0;
347+
#[cfg(stage0)] pub const POST_DROP_U32: u32 = 0;
348+
#[cfg(stage0)] pub const POST_DROP_U64: u64 = 0;
349+
#[cfg(stage0)] pub const POST_DROP_USIZE: usize = 0;
350+
294351
/// Interprets `src` as `&U`, and then reads `src` without moving the contained value.
295352
///
296353
/// This function will unsafely assume the pointer `src` is valid for `sizeof(U)` bytes by

src/libcore/ptr.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,21 @@ pub unsafe fn read_and_zero<T>(dest: *mut T) -> T {
245245
tmp
246246
}
247247

248+
/// Variant of read_and_zero that writes the specific drop-flag byte
249+
/// (which may be more apropriate than zero).
250+
#[inline(always)]
251+
#[unstable(feature = "core",
252+
reason = "may play a larger role in std::ptr future extensions")]
253+
pub unsafe fn read_and_drop<T>(dest: *mut T) -> T {
254+
// Copy the data out from `dest`:
255+
let tmp = read(&*dest);
256+
257+
// Now mark `dest` as dropped:
258+
write_bytes(dest, mem::POST_DROP_U8, 1);
259+
260+
tmp
261+
}
262+
248263
/// Overwrites a memory location with the given value without reading or
249264
/// dropping the old value.
250265
///

src/librustc_trans/trans/_match.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1524,7 +1524,7 @@ pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
15241524
let scope = cleanup::var_scope(tcx, p_id);
15251525
bcx = mk_binding_alloca(
15261526
bcx, p_id, &path1.node, scope, (),
1527-
|(), bcx, llval, ty| { zero_mem(bcx, llval, ty); bcx });
1527+
|(), bcx, llval, ty| { drop_done_fill_mem(bcx, llval, ty); bcx });
15281528
});
15291529
bcx
15301530
}

0 commit comments

Comments
 (0)