Skip to content

Commit ba13482

Browse files
committed
update ptr intrinsics and rewrite vec routines to be more correct.
In particular, it is not valid to go around passing uninitialized or zero'd memory as arguments. Rust should generally be free to assume that the arguments it gets are valid input values, but the output of intrinsics::uninit() and intrinsics::init() are not (e.g., an @t is just null, leading to an error if we should try to increment the ref count).
1 parent 1670a8c commit ba13482

File tree

2 files changed

+144
-40
lines changed

2 files changed

+144
-40
lines changed

src/libstd/ptr.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,30 @@ pub unsafe fn set_memory<T>(dst: *mut T, c: u8, count: uint) {
142142
memset64(dst, c, count as u64);
143143
}
144144

145+
/**
146+
* Zeroes out `count` bytes of memory at `dst`
147+
*/
148+
#[inline]
149+
#[cfg(not(stage0))]
150+
pub unsafe fn zero_memory<T>(dst: *mut T, count: uint) {
151+
set_memory(dst, 0, count);
152+
}
153+
154+
/**
155+
* Zeroes out `count * size_of::<T>` bytes of memory at `dst`
156+
*/
157+
#[inline]
158+
#[cfg(stage0)]
159+
pub unsafe fn zero_memory<T>(dst: *mut T, count: uint) {
160+
let mut count = count * sys::size_of::<T>();
161+
let mut dst = dst as *mut u8;
162+
while count > 0 {
163+
*dst = 0;
164+
dst = mut_offset(dst, 1);
165+
count -= 1;
166+
}
167+
}
168+
145169
/**
146170
* Swap the values at two mutable locations of the same type, without
147171
* deinitialising or copying either one.
@@ -172,6 +196,32 @@ pub unsafe fn replace_ptr<T>(dest: *mut T, mut src: T) -> T {
172196
src
173197
}
174198

199+
/**
200+
* Reads the value from `*src` and returns it. Does not copy `*src`.
201+
*/
202+
#[inline(always)]
203+
pub unsafe fn read_ptr<T>(src: *mut T) -> T {
204+
let mut tmp: T = intrinsics::uninit();
205+
let t: *mut T = &mut tmp;
206+
copy_memory(t, src, 1);
207+
tmp
208+
}
209+
210+
/**
211+
* Reads the value from `*src` and nulls it out.
212+
* This currently prevents destructors from executing.
213+
*/
214+
#[inline(always)]
215+
pub unsafe fn read_and_zero_ptr<T>(dest: *mut T) -> T {
216+
// Copy the data out from `dest`:
217+
let tmp = read_ptr(dest);
218+
219+
// Now zero out `dest`:
220+
zero_memory(dest, 1);
221+
222+
tmp
223+
}
224+
175225
/// Transform a region pointer - &T - to an unsafe pointer - *T.
176226
#[inline]
177227
pub fn to_unsafe_ptr<T>(thing: &T) -> *T {

src/libstd/vec.rs

Lines changed: 94 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,16 +1256,15 @@ impl<T> OwnedVector<T> for ~[T] {
12561256
/// ~~~
12571257
#[inline]
12581258
fn push_all_move(&mut self, mut rhs: ~[T]) {
1259-
let new_len = self.len() + rhs.len();
1259+
let self_len = self.len();
1260+
let rhs_len = rhs.len();
1261+
let new_len = self_len + rhs_len;
12601262
self.reserve(new_len);
1261-
unsafe {
1262-
do rhs.as_mut_buf |p, len| {
1263-
for uint::range(0, len) |i| {
1264-
let x = ptr::replace_ptr(ptr::mut_offset(p, i),
1265-
intrinsics::uninit());
1266-
self.push(x);
1267-
}
1268-
}
1263+
unsafe { // Note: infallible.
1264+
let self_p = vec::raw::to_mut_ptr(*self);
1265+
let rhs_p = vec::raw::to_ptr(rhs);
1266+
ptr::copy_memory(ptr::mut_offset(self_p, self_len), rhs_p, rhs_len);
1267+
raw::set_len(self, new_len);
12691268
raw::set_len(&mut rhs, 0);
12701269
}
12711270
}
@@ -1277,9 +1276,8 @@ impl<T> OwnedVector<T> for ~[T] {
12771276
ln => {
12781277
let valptr = ptr::to_mut_unsafe_ptr(&mut self[ln - 1u]);
12791278
unsafe {
1280-
let val = ptr::replace_ptr(valptr, intrinsics::init());
1281-
raw::set_len(self, ln - 1u);
1282-
Some(val)
1279+
raw::set_len(v, ln - 1u);
1280+
ptr::read_ptr(valptr)
12831281
}
12841282
}
12851283
}
@@ -1410,7 +1408,7 @@ impl<T> OwnedVector<T> for ~[T] {
14101408
unsafe {
14111409
// This loop is optimized out for non-drop types.
14121410
for uint::range(newlen, oldlen) |i| {
1413-
ptr::replace_ptr(ptr::mut_offset(p, i), intrinsics::uninit());
1411+
ptr::read_and_zero_ptr(ptr::mut_offset(p, i))
14141412
}
14151413
}
14161414
}
@@ -1555,37 +1553,93 @@ pub trait OwnedEqVector<T:Eq> {
15551553

15561554
impl<T:Eq> OwnedEqVector<T> for ~[T] {
15571555
/**
1558-
* Remove consecutive repeated elements from a vector; if the vector is
1559-
* sorted, this removes all duplicates.
1560-
*/
1561-
pub fn dedup(&mut self) {
1556+
* Remove consecutive repeated elements from a vector; if the vector is
1557+
* sorted, this removes all duplicates.
1558+
*/
1559+
pub fn dedup<T:Eq>(&mut self) {
15621560
unsafe {
1563-
if self.len() == 0 { return; }
1564-
let mut last_written = 0;
1565-
let mut next_to_read = 1;
1566-
do self.as_mut_buf |p, ln| {
1567-
// last_written < next_to_read <= ln
1568-
while next_to_read < ln {
1569-
// last_written < next_to_read < ln
1570-
if *ptr::mut_offset(p, next_to_read) ==
1571-
*ptr::mut_offset(p, last_written) {
1572-
ptr::replace_ptr(ptr::mut_offset(p, next_to_read),
1573-
intrinsics::uninit());
1574-
} else {
1575-
last_written += 1;
1576-
// last_written <= next_to_read < ln
1577-
if next_to_read != last_written {
1578-
ptr::swap_ptr(ptr::mut_offset(p, last_written),
1579-
ptr::mut_offset(p, next_to_read));
1580-
}
1561+
// Although we have a mutable reference to `self`, we cannot make
1562+
// *arbitrary* changes. There exists the possibility that this
1563+
// vector is contained with an `@mut` box and hence is still
1564+
// readable by the outside world during the `Eq` comparisons.
1565+
// Moreover, those comparisons could fail, so we must ensure
1566+
// that the vector is in a valid state at all time.
1567+
//
1568+
// The way that we handle this is by using swaps; we iterate
1569+
// over all the elements, swapping as we go so that at the end
1570+
// the elements we wish to keep are in the front, and those we
1571+
// wish to reject are at the back. We can then truncate the
1572+
// vector. This operation is still O(n).
1573+
//
1574+
// Example: We start in this state, where `r` represents "next
1575+
// read" and `w` represents "next_write`.
1576+
//
1577+
// r
1578+
// +---+---+---+---+---+---+
1579+
// | 0 | 1 | 1 | 2 | 3 | 3 |
1580+
// +---+---+---+---+---+---+
1581+
// w
1582+
//
1583+
// Comparing self[r] against self[w-1], tis is not a duplicate, so
1584+
// we swap self[r] and self[w] (no effect as r==w) and then increment both
1585+
// r and w, leaving us with:
1586+
//
1587+
// r
1588+
// +---+---+---+---+---+---+
1589+
// | 0 | 1 | 1 | 2 | 3 | 3 |
1590+
// +---+---+---+---+---+---+
1591+
// w
1592+
//
1593+
// Comparing self[r] against self[w-1], this value is a duplicate,
1594+
// so we increment `r` but leave everything else unchanged:
1595+
//
1596+
// r
1597+
// +---+---+---+---+---+---+
1598+
// | 0 | 1 | 1 | 2 | 3 | 3 |
1599+
// +---+---+---+---+---+---+
1600+
// w
1601+
//
1602+
// Comparing self[r] against self[w-1], this is not a duplicate,
1603+
// so swap self[r] and self[w] and advance r and w:
1604+
//
1605+
// r
1606+
// +---+---+---+---+---+---+
1607+
// | 0 | 1 | 2 | 1 | 3 | 3 |
1608+
// +---+---+---+---+---+---+
1609+
// w
1610+
//
1611+
// Not a duplicate, repeat:
1612+
//
1613+
// r
1614+
// +---+---+---+---+---+---+
1615+
// | 0 | 1 | 2 | 3 | 1 | 3 |
1616+
// +---+---+---+---+---+---+
1617+
// w
1618+
//
1619+
// Duplicate, advance r. End of vec. Truncate to w.
1620+
1621+
let ln = self.len();
1622+
if ln < 1 { return; }
1623+
1624+
// Avoid bounds checks by using unsafe pointers.
1625+
let p = vec::raw::to_mut_ptr(*self);
1626+
let mut r = 1;
1627+
let mut w = 1;
1628+
1629+
while r < ln {
1630+
let p_r = ptr::mut_offset(p, r);
1631+
let p_wm1 = ptr::mut_offset(p, w - 1);
1632+
if *p_r != *p_wm1 {
1633+
if r != w {
1634+
let p_w = ptr::mut_offset(p_wm1, 1);
1635+
util::swap(&mut *p_r, &mut *p_w);
15811636
}
1582-
// last_written <= next_to_read < ln
1583-
next_to_read += 1;
1584-
// last_written < next_to_read <= ln
1637+
w += 1;
15851638
}
1639+
r += 1;
15861640
}
1587-
// last_written < next_to_read == ln
1588-
raw::set_len(self, last_written + 1);
1641+
1642+
self.truncate(w);
15891643
}
15901644
}
15911645
}

0 commit comments

Comments
 (0)