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

Backport accepted PRs to beta #26161

Merged
merged 6 commits into from
Jun 11, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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