Skip to content

Commit

Permalink
Merge pull request #26161 from alexcrichton/beta-backport
Browse files Browse the repository at this point in the history
Backport accepted PRs to beta
  • Loading branch information
brson committed Jun 11, 2015
2 parents e904638 + 48ff33c commit 4efc4ec
Show file tree
Hide file tree
Showing 9 changed files with 257 additions and 39 deletions.
4 changes: 0 additions & 4 deletions mk/main.mk
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,6 @@ ifneq ($(wildcard $(subst $(SPACE),\$(SPACE),$(CFG_GIT_DIR))),)
endif
endif

CFG_BUILD_DATE = $(shell date +%F)
CFG_VERSION += (built $(CFG_BUILD_DATE))

# Windows exe's need numeric versions - don't use anything but
# numbers and dots here
CFG_VERSION_WIN = $(CFG_RELEASE_NUM)
Expand Down Expand Up @@ -333,7 +330,6 @@ endif
ifdef CFG_VER_HASH
export CFG_VER_HASH
endif
export CFG_BUILD_DATE
export CFG_VERSION
export CFG_VERSION_WIN
export CFG_RELEASE
Expand Down
113 changes: 88 additions & 25 deletions src/libcollections/binary_heap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@
use core::prelude::*;

use core::iter::{FromIterator};
use core::mem::{zeroed, replace, swap};
use core::mem::swap;
use core::ptr;

use slice;
Expand Down Expand Up @@ -484,46 +484,42 @@ impl<T: Ord> BinaryHeap<T> {

// The implementations of sift_up and sift_down use unsafe blocks in
// order to move an element out of the vector (leaving behind a
// zeroed element), shift along the others and move it back into the
// vector over the junk element. This reduces the constant factor
// compared to using swaps, which involves twice as many moves.
fn sift_up(&mut self, start: usize, mut pos: usize) {
// hole), shift along the others and move the removed element back into the
// vector at the final location of the hole.
// The `Hole` type is used to represent this, and make sure
// the hole is filled back at the end of its scope, even on panic.
// Using a hole reduces the constant factor compared to using swaps,
// which involves twice as many moves.
fn sift_up(&mut self, start: usize, pos: usize) {
unsafe {
let new = replace(&mut self.data[pos], zeroed());
// Take out the value at `pos` and create a hole.
let mut hole = Hole::new(&mut self.data, pos);

while pos > start {
let parent = (pos - 1) >> 1;

if new <= self.data[parent] { break; }

let x = replace(&mut self.data[parent], zeroed());
ptr::write(&mut self.data[pos], x);
pos = parent;
while hole.pos() > start {
let parent = (hole.pos() - 1) / 2;
if hole.removed() <= hole.get(parent) { break }
hole.move_to(parent);
}
ptr::write(&mut self.data[pos], new);
}
}

fn sift_down_range(&mut self, mut pos: usize, end: usize) {
let start = pos;
unsafe {
let start = pos;
let new = replace(&mut self.data[pos], zeroed());

let mut hole = Hole::new(&mut self.data, pos);
let mut child = 2 * pos + 1;
while child < end {
let right = child + 1;
if right < end && !(self.data[child] > self.data[right]) {
if right < end && !(hole.get(child) > hole.get(right)) {
child = right;
}
let x = replace(&mut self.data[child], zeroed());
ptr::write(&mut self.data[pos], x);
pos = child;
child = 2 * pos + 1;
hole.move_to(child);
child = 2 * hole.pos() + 1;
}

ptr::write(&mut self.data[pos], new);
self.sift_up(start, pos);
pos = hole.pos;
}
self.sift_up(start, pos);
}

fn sift_down(&mut self, pos: usize) {
Expand Down Expand Up @@ -554,6 +550,73 @@ impl<T: Ord> BinaryHeap<T> {
pub fn clear(&mut self) { self.drain(); }
}

/// Hole represents a hole in a slice i.e. an index without valid value
/// (because it was moved from or duplicated).
/// In drop, `Hole` will restore the slice by filling the hole
/// position with the value that was originally removed.
struct Hole<'a, T: 'a> {
data: &'a mut [T],
/// `elt` is always `Some` from new until drop.
elt: Option<T>,
pos: usize,
}

impl<'a, T> Hole<'a, T> {
/// Create a new Hole at index `pos`.
fn new(data: &'a mut [T], pos: usize) -> Self {
unsafe {
let elt = ptr::read(&data[pos]);
Hole {
data: data,
elt: Some(elt),
pos: pos,
}
}
}

#[inline(always)]
fn pos(&self) -> usize { self.pos }

/// Return a reference to the element removed
#[inline(always)]
fn removed(&self) -> &T {
self.elt.as_ref().unwrap()
}

/// Return a reference to the element at `index`.
///
/// Panics if the index is out of bounds.
///
/// Unsafe because index must not equal pos.
#[inline(always)]
unsafe fn get(&self, index: usize) -> &T {
debug_assert!(index != self.pos);
&self.data[index]
}

/// Move hole to new location
///
/// Unsafe because index must not equal pos.
#[inline(always)]
unsafe fn move_to(&mut self, index: usize) {
debug_assert!(index != self.pos);
let index_ptr: *const _ = &self.data[index];
let hole_ptr = &mut self.data[self.pos];
ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1);
self.pos = index;
}
}

impl<'a, T> Drop for Hole<'a, T> {
fn drop(&mut self) {
// fill the hole again
unsafe {
let pos = self.pos;
ptr::write(&mut self.data[pos], self.elt.take().unwrap());
}
}
}

/// `BinaryHeap` iterator.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Iter <'a, T: 'a> {
Expand Down
26 changes: 26 additions & 0 deletions src/libcollections/linked_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,13 @@ impl<T> LinkedList<T> {
length: len - at
};

// Swap split_node.next with list_head (which is None), nulling out split_node.next,
// as it is the new tail.
mem::swap(&mut split_node.resolve().unwrap().next, &mut splitted_list.list_head);
// Null out list_head.prev. Note this `unwrap` won't fail because if at == len
// we already branched out at the top of the fn to return the empty list.
splitted_list.list_head.as_mut().unwrap().prev = Rawlink::none();
// Fix the tail ptr
self.list_tail = split_node;
self.length = at;

Expand Down Expand Up @@ -1082,6 +1088,26 @@ mod tests {
}
}

#[test]
fn test_26021() {
use std::iter::ExactSizeIterator;
// There was a bug in split_off that failed to null out the RHS's head's prev ptr.
// This caused the RHS's dtor to walk up into the LHS at drop and delete all of
// its nodes.
//
// https://github.com/rust-lang/rust/issues/26021
let mut v1 = LinkedList::new();
v1.push_front(1u8);
v1.push_front(1u8);
v1.push_front(1u8);
v1.push_front(1u8);
let _ = v1.split_off(3); // Dropping this now should not cause laundry consumption
assert_eq!(v1.len(), 3);

assert_eq!(v1.iter().len(), 3);
assert_eq!(v1.iter().collect::<Vec<_>>().len(), 3);
}

#[cfg(test)]
fn fuzz_test(sz: i32) {
let mut m: LinkedList<_> = LinkedList::new();
Expand Down
2 changes: 1 addition & 1 deletion src/libcore/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1370,7 +1370,7 @@ impl<T: Clone> MinMaxResult<T> {
}

/// An iterator that clones the elements of an underlying iterator
#[unstable(feature = "core", reason = "recent addition")]
#[stable(feature = "iter_cloned", since = "1.1.0")]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Clone)]
pub struct Cloned<I> {
Expand Down
15 changes: 12 additions & 3 deletions src/libcore/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -563,13 +563,22 @@ macro_rules! int_impl {
acc
}

/// Computes the absolute value of `self`. `Int::min_value()` will be
/// returned if the number is `Int::min_value()`.
/// Computes the absolute value of `self`.
///
/// # Overflow behavior
///
/// The absolute value of `i32::min_value()` cannot be represented as an
/// `i32`, and attempting to calculate it will cause an overflow. This
/// means that code in debug mode will trigger a panic on this case and
/// optimized code will return `i32::min_value()` without a panic.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn abs(self) -> $T {
if self.is_negative() {
self.wrapping_neg()
// Note that the #[inline] above means that the overflow
// semantics of this negation depend on the crate we're being
// inlined into.
-self
} else {
self
}
Expand Down
5 changes: 0 additions & 5 deletions src/librustc_driver/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,10 +483,6 @@ pub fn commit_date_str() -> Option<&'static str> {
option_env!("CFG_VER_DATE")
}

pub fn build_date_str() -> Option<&'static str> {
option_env!("CFG_BUILD_DATE")
}

/// Prints version information and returns None on success or an error
/// message on panic.
pub fn version(binary: &str, matches: &getopts::Matches) {
Expand All @@ -498,7 +494,6 @@ pub fn version(binary: &str, matches: &getopts::Matches) {
println!("binary: {}", binary);
println!("commit-hash: {}", unw(commit_hash_str()));
println!("commit-date: {}", unw(commit_date_str()));
println!("build-date: {}", unw(build_date_str()));
println!("host: {}", config::host_triple());
println!("release: {}", unw(release_str()));
}
Expand Down
2 changes: 1 addition & 1 deletion src/libstd/net/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use sys_common::net as net_imp;

pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
pub use self::addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
pub use self::tcp::{TcpStream, TcpListener};
pub use self::tcp::{TcpStream, TcpListener, Incoming};
pub use self::udp::UdpSocket;
pub use self::parser::AddrParseError;

Expand Down
108 changes: 108 additions & 0 deletions src/test/run-pass/binary-heap-panic-safe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(std_misc, collections, catch_panic, rand)]

use std::__rand::{thread_rng, Rng};
use std::thread;

use std::collections::BinaryHeap;
use std::cmp;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};

static DROP_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;

// old binaryheap failed this test
//
// Integrity means that all elements are present after a comparison panics,
// even if the order may not be correct.
//
// Destructors must be called exactly once per element.
fn test_integrity() {
#[derive(Eq, PartialEq, Ord, Clone, Debug)]
struct PanicOrd<T>(T, bool);

impl<T> Drop for PanicOrd<T> {
fn drop(&mut self) {
// update global drop count
DROP_COUNTER.fetch_add(1, Ordering::SeqCst);
}
}

impl<T: PartialOrd> PartialOrd for PanicOrd<T> {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
if self.1 || other.1 {
panic!("Panicking comparison");
}
self.0.partial_cmp(&other.0)
}
}
let mut rng = thread_rng();
const DATASZ: usize = 32;
const NTEST: usize = 10;

// don't use 0 in the data -- we want to catch the zeroed-out case.
let data = (1..DATASZ + 1).collect::<Vec<_>>();

// since it's a fuzzy test, run several tries.
for _ in 0..NTEST {
for i in 1..DATASZ + 1 {
DROP_COUNTER.store(0, Ordering::SeqCst);

let mut panic_ords: Vec<_> = data.iter()
.filter(|&&x| x != i)
.map(|&x| PanicOrd(x, false))
.collect();
let panic_item = PanicOrd(i, true);

// heapify the sane items
rng.shuffle(&mut panic_ords);
let heap = Arc::new(Mutex::new(BinaryHeap::from_vec(panic_ords)));
let inner_data;

{
let heap_ref = heap.clone();


// push the panicking item to the heap and catch the panic
let thread_result = thread::catch_panic(move || {
heap.lock().unwrap().push(panic_item);
});
assert!(thread_result.is_err());

// Assert no elements were dropped
let drops = DROP_COUNTER.load(Ordering::SeqCst);
//assert!(drops == 0, "Must not drop items. drops={}", drops);

{
// now fetch the binary heap's data vector
let mutex_guard = match heap_ref.lock() {
Ok(x) => x,
Err(poison) => poison.into_inner(),
};
inner_data = mutex_guard.clone().into_vec();
}
}
let drops = DROP_COUNTER.load(Ordering::SeqCst);
assert_eq!(drops, DATASZ);

let mut data_sorted = inner_data.into_iter().map(|p| p.0).collect::<Vec<_>>();
data_sorted.sort();
assert_eq!(data_sorted, data);
}
}
}

fn main() {
test_integrity();
}

Loading

0 comments on commit 4efc4ec

Please sign in to comment.