Skip to content

Commit 4efc4ec

Browse files
committed
Merge pull request #26161 from alexcrichton/beta-backport
Backport accepted PRs to beta
2 parents e904638 + 48ff33c commit 4efc4ec

File tree

9 files changed

+257
-39
lines changed

9 files changed

+257
-39
lines changed

mk/main.mk

-4
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,6 @@ ifneq ($(wildcard $(subst $(SPACE),\$(SPACE),$(CFG_GIT_DIR))),)
7474
endif
7575
endif
7676

77-
CFG_BUILD_DATE = $(shell date +%F)
78-
CFG_VERSION += (built $(CFG_BUILD_DATE))
79-
8077
# Windows exe's need numeric versions - don't use anything but
8178
# numbers and dots here
8279
CFG_VERSION_WIN = $(CFG_RELEASE_NUM)
@@ -333,7 +330,6 @@ endif
333330
ifdef CFG_VER_HASH
334331
export CFG_VER_HASH
335332
endif
336-
export CFG_BUILD_DATE
337333
export CFG_VERSION
338334
export CFG_VERSION_WIN
339335
export CFG_RELEASE

src/libcollections/binary_heap.rs

+88-25
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@
153153
use core::prelude::*;
154154

155155
use core::iter::{FromIterator};
156-
use core::mem::{zeroed, replace, swap};
156+
use core::mem::swap;
157157
use core::ptr;
158158

159159
use slice;
@@ -484,46 +484,42 @@ impl<T: Ord> BinaryHeap<T> {
484484

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

494-
while pos > start {
495-
let parent = (pos - 1) >> 1;
496-
497-
if new <= self.data[parent] { break; }
498-
499-
let x = replace(&mut self.data[parent], zeroed());
500-
ptr::write(&mut self.data[pos], x);
501-
pos = parent;
498+
while hole.pos() > start {
499+
let parent = (hole.pos() - 1) / 2;
500+
if hole.removed() <= hole.get(parent) { break }
501+
hole.move_to(parent);
502502
}
503-
ptr::write(&mut self.data[pos], new);
504503
}
505504
}
506505

507506
fn sift_down_range(&mut self, mut pos: usize, end: usize) {
507+
let start = pos;
508508
unsafe {
509-
let start = pos;
510-
let new = replace(&mut self.data[pos], zeroed());
511-
509+
let mut hole = Hole::new(&mut self.data, pos);
512510
let mut child = 2 * pos + 1;
513511
while child < end {
514512
let right = child + 1;
515-
if right < end && !(self.data[child] > self.data[right]) {
513+
if right < end && !(hole.get(child) > hole.get(right)) {
516514
child = right;
517515
}
518-
let x = replace(&mut self.data[child], zeroed());
519-
ptr::write(&mut self.data[pos], x);
520-
pos = child;
521-
child = 2 * pos + 1;
516+
hole.move_to(child);
517+
child = 2 * hole.pos() + 1;
522518
}
523519

524-
ptr::write(&mut self.data[pos], new);
525-
self.sift_up(start, pos);
520+
pos = hole.pos;
526521
}
522+
self.sift_up(start, pos);
527523
}
528524

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

553+
/// Hole represents a hole in a slice i.e. an index without valid value
554+
/// (because it was moved from or duplicated).
555+
/// In drop, `Hole` will restore the slice by filling the hole
556+
/// position with the value that was originally removed.
557+
struct Hole<'a, T: 'a> {
558+
data: &'a mut [T],
559+
/// `elt` is always `Some` from new until drop.
560+
elt: Option<T>,
561+
pos: usize,
562+
}
563+
564+
impl<'a, T> Hole<'a, T> {
565+
/// Create a new Hole at index `pos`.
566+
fn new(data: &'a mut [T], pos: usize) -> Self {
567+
unsafe {
568+
let elt = ptr::read(&data[pos]);
569+
Hole {
570+
data: data,
571+
elt: Some(elt),
572+
pos: pos,
573+
}
574+
}
575+
}
576+
577+
#[inline(always)]
578+
fn pos(&self) -> usize { self.pos }
579+
580+
/// Return a reference to the element removed
581+
#[inline(always)]
582+
fn removed(&self) -> &T {
583+
self.elt.as_ref().unwrap()
584+
}
585+
586+
/// Return a reference to the element at `index`.
587+
///
588+
/// Panics if the index is out of bounds.
589+
///
590+
/// Unsafe because index must not equal pos.
591+
#[inline(always)]
592+
unsafe fn get(&self, index: usize) -> &T {
593+
debug_assert!(index != self.pos);
594+
&self.data[index]
595+
}
596+
597+
/// Move hole to new location
598+
///
599+
/// Unsafe because index must not equal pos.
600+
#[inline(always)]
601+
unsafe fn move_to(&mut self, index: usize) {
602+
debug_assert!(index != self.pos);
603+
let index_ptr: *const _ = &self.data[index];
604+
let hole_ptr = &mut self.data[self.pos];
605+
ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1);
606+
self.pos = index;
607+
}
608+
}
609+
610+
impl<'a, T> Drop for Hole<'a, T> {
611+
fn drop(&mut self) {
612+
// fill the hole again
613+
unsafe {
614+
let pos = self.pos;
615+
ptr::write(&mut self.data[pos], self.elt.take().unwrap());
616+
}
617+
}
618+
}
619+
557620
/// `BinaryHeap` iterator.
558621
#[stable(feature = "rust1", since = "1.0.0")]
559622
pub struct Iter <'a, T: 'a> {

src/libcollections/linked_list.rs

+26
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,13 @@ impl<T> LinkedList<T> {
616616
length: len - at
617617
};
618618

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

@@ -1082,6 +1088,26 @@ mod tests {
10821088
}
10831089
}
10841090

1091+
#[test]
1092+
fn test_26021() {
1093+
use std::iter::ExactSizeIterator;
1094+
// There was a bug in split_off that failed to null out the RHS's head's prev ptr.
1095+
// This caused the RHS's dtor to walk up into the LHS at drop and delete all of
1096+
// its nodes.
1097+
//
1098+
// https://github.com/rust-lang/rust/issues/26021
1099+
let mut v1 = LinkedList::new();
1100+
v1.push_front(1u8);
1101+
v1.push_front(1u8);
1102+
v1.push_front(1u8);
1103+
v1.push_front(1u8);
1104+
let _ = v1.split_off(3); // Dropping this now should not cause laundry consumption
1105+
assert_eq!(v1.len(), 3);
1106+
1107+
assert_eq!(v1.iter().len(), 3);
1108+
assert_eq!(v1.iter().collect::<Vec<_>>().len(), 3);
1109+
}
1110+
10851111
#[cfg(test)]
10861112
fn fuzz_test(sz: i32) {
10871113
let mut m: LinkedList<_> = LinkedList::new();

src/libcore/iter.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1370,7 +1370,7 @@ impl<T: Clone> MinMaxResult<T> {
13701370
}
13711371

13721372
/// An iterator that clones the elements of an underlying iterator
1373-
#[unstable(feature = "core", reason = "recent addition")]
1373+
#[stable(feature = "iter_cloned", since = "1.1.0")]
13741374
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
13751375
#[derive(Clone)]
13761376
pub struct Cloned<I> {

src/libcore/num/mod.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -563,13 +563,22 @@ macro_rules! int_impl {
563563
acc
564564
}
565565

566-
/// Computes the absolute value of `self`. `Int::min_value()` will be
567-
/// returned if the number is `Int::min_value()`.
566+
/// Computes the absolute value of `self`.
567+
///
568+
/// # Overflow behavior
569+
///
570+
/// The absolute value of `i32::min_value()` cannot be represented as an
571+
/// `i32`, and attempting to calculate it will cause an overflow. This
572+
/// means that code in debug mode will trigger a panic on this case and
573+
/// optimized code will return `i32::min_value()` without a panic.
568574
#[stable(feature = "rust1", since = "1.0.0")]
569575
#[inline]
570576
pub fn abs(self) -> $T {
571577
if self.is_negative() {
572-
self.wrapping_neg()
578+
// Note that the #[inline] above means that the overflow
579+
// semantics of this negation depend on the crate we're being
580+
// inlined into.
581+
-self
573582
} else {
574583
self
575584
}

src/librustc_driver/lib.rs

-5
Original file line numberDiff line numberDiff line change
@@ -483,10 +483,6 @@ pub fn commit_date_str() -> Option<&'static str> {
483483
option_env!("CFG_VER_DATE")
484484
}
485485

486-
pub fn build_date_str() -> Option<&'static str> {
487-
option_env!("CFG_BUILD_DATE")
488-
}
489-
490486
/// Prints version information and returns None on success or an error
491487
/// message on panic.
492488
pub fn version(binary: &str, matches: &getopts::Matches) {
@@ -498,7 +494,6 @@ pub fn version(binary: &str, matches: &getopts::Matches) {
498494
println!("binary: {}", binary);
499495
println!("commit-hash: {}", unw(commit_hash_str()));
500496
println!("commit-date: {}", unw(commit_date_str()));
501-
println!("build-date: {}", unw(build_date_str()));
502497
println!("host: {}", config::host_triple());
503498
println!("release: {}", unw(release_str()));
504499
}

src/libstd/net/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use sys_common::net as net_imp;
1919

2020
pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
2121
pub use self::addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
22-
pub use self::tcp::{TcpStream, TcpListener};
22+
pub use self::tcp::{TcpStream, TcpListener, Incoming};
2323
pub use self::udp::UdpSocket;
2424
pub use self::parser::AddrParseError;
2525

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(std_misc, collections, catch_panic, rand)]
12+
13+
use std::__rand::{thread_rng, Rng};
14+
use std::thread;
15+
16+
use std::collections::BinaryHeap;
17+
use std::cmp;
18+
use std::sync::Arc;
19+
use std::sync::Mutex;
20+
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
21+
22+
static DROP_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
23+
24+
// old binaryheap failed this test
25+
//
26+
// Integrity means that all elements are present after a comparison panics,
27+
// even if the order may not be correct.
28+
//
29+
// Destructors must be called exactly once per element.
30+
fn test_integrity() {
31+
#[derive(Eq, PartialEq, Ord, Clone, Debug)]
32+
struct PanicOrd<T>(T, bool);
33+
34+
impl<T> Drop for PanicOrd<T> {
35+
fn drop(&mut self) {
36+
// update global drop count
37+
DROP_COUNTER.fetch_add(1, Ordering::SeqCst);
38+
}
39+
}
40+
41+
impl<T: PartialOrd> PartialOrd for PanicOrd<T> {
42+
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
43+
if self.1 || other.1 {
44+
panic!("Panicking comparison");
45+
}
46+
self.0.partial_cmp(&other.0)
47+
}
48+
}
49+
let mut rng = thread_rng();
50+
const DATASZ: usize = 32;
51+
const NTEST: usize = 10;
52+
53+
// don't use 0 in the data -- we want to catch the zeroed-out case.
54+
let data = (1..DATASZ + 1).collect::<Vec<_>>();
55+
56+
// since it's a fuzzy test, run several tries.
57+
for _ in 0..NTEST {
58+
for i in 1..DATASZ + 1 {
59+
DROP_COUNTER.store(0, Ordering::SeqCst);
60+
61+
let mut panic_ords: Vec<_> = data.iter()
62+
.filter(|&&x| x != i)
63+
.map(|&x| PanicOrd(x, false))
64+
.collect();
65+
let panic_item = PanicOrd(i, true);
66+
67+
// heapify the sane items
68+
rng.shuffle(&mut panic_ords);
69+
let heap = Arc::new(Mutex::new(BinaryHeap::from_vec(panic_ords)));
70+
let inner_data;
71+
72+
{
73+
let heap_ref = heap.clone();
74+
75+
76+
// push the panicking item to the heap and catch the panic
77+
let thread_result = thread::catch_panic(move || {
78+
heap.lock().unwrap().push(panic_item);
79+
});
80+
assert!(thread_result.is_err());
81+
82+
// Assert no elements were dropped
83+
let drops = DROP_COUNTER.load(Ordering::SeqCst);
84+
//assert!(drops == 0, "Must not drop items. drops={}", drops);
85+
86+
{
87+
// now fetch the binary heap's data vector
88+
let mutex_guard = match heap_ref.lock() {
89+
Ok(x) => x,
90+
Err(poison) => poison.into_inner(),
91+
};
92+
inner_data = mutex_guard.clone().into_vec();
93+
}
94+
}
95+
let drops = DROP_COUNTER.load(Ordering::SeqCst);
96+
assert_eq!(drops, DATASZ);
97+
98+
let mut data_sorted = inner_data.into_iter().map(|p| p.0).collect::<Vec<_>>();
99+
data_sorted.sort();
100+
assert_eq!(data_sorted, data);
101+
}
102+
}
103+
}
104+
105+
fn main() {
106+
test_integrity();
107+
}
108+

0 commit comments

Comments
 (0)