Skip to content

Commit 9b21bf4

Browse files
alexcrichtonthestinger
authored andcommitted
Account for possible 0-sized elements in vector iterators
Closes #7733
1 parent 1ec06e0 commit 9b21bf4

File tree

1 file changed

+68
-13
lines changed

1 file changed

+68
-13
lines changed

src/libstd/vec.rs

+68-13
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ use ptr::RawPtr;
3030
use rt::global_heap::malloc_raw;
3131
use rt::global_heap::realloc_raw;
3232
use sys;
33-
use sys::size_of;
3433
use uint;
3534
use unstable::intrinsics;
3635
#[cfg(stage0)]
@@ -109,7 +108,7 @@ pub fn with_capacity<T>(capacity: uint) -> ~[T] {
109108
vec
110109
} else {
111110
let alloc = capacity * sys::nonzero_size_of::<T>();
112-
let ptr = malloc_raw(alloc + size_of::<raw::VecRepr>()) as *mut raw::VecRepr;
111+
let ptr = malloc_raw(alloc + sys::size_of::<raw::VecRepr>()) as *mut raw::VecRepr;
113112
(*ptr).unboxed.alloc = alloc;
114113
(*ptr).unboxed.fill = 0;
115114
cast::transmute(ptr)
@@ -751,7 +750,9 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] {
751750
fn iter(self) -> VecIterator<'self, T> {
752751
unsafe {
753752
let p = vec::raw::to_ptr(self);
754-
VecIterator{ptr: p, end: p.offset(self.len()),
753+
VecIterator{ptr: p,
754+
end: cast::transmute(p as uint + self.len() *
755+
sys::nonzero_size_of::<T>()),
755756
lifetime: cast::transmute(p)}
756757
}
757758
}
@@ -1149,7 +1150,7 @@ impl<T> OwnedVector<T> for ~[T] {
11491150
::at_vec::raw::reserve_raw(td, ptr, n);
11501151
} else {
11511152
let alloc = n * sys::nonzero_size_of::<T>();
1152-
*ptr = realloc_raw(*ptr as *mut c_void, alloc + size_of::<raw::VecRepr>())
1153+
*ptr = realloc_raw(*ptr as *mut c_void, alloc + sys::size_of::<raw::VecRepr>())
11531154
as *mut raw::VecRepr;
11541155
(**ptr).unboxed.alloc = alloc;
11551156
}
@@ -1178,7 +1179,7 @@ impl<T> OwnedVector<T> for ~[T] {
11781179
::at_vec::raw::reserve_raw(td, ptr, n);
11791180
} else {
11801181
let alloc = n * sys::nonzero_size_of::<T>();
1181-
let size = alloc + size_of::<raw::VecRepr>();
1182+
let size = alloc + sys::size_of::<raw::VecRepr>();
11821183
if alloc / sys::nonzero_size_of::<T>() != n || size < alloc {
11831184
fail!("vector size is too large: %u", n);
11841185
}
@@ -1712,7 +1713,9 @@ impl<'self,T> MutableVector<'self, T> for &'self mut [T] {
17121713
fn mut_iter(self) -> VecMutIterator<'self, T> {
17131714
unsafe {
17141715
let p = vec::raw::to_mut_ptr(self);
1715-
VecMutIterator{ptr: p, end: p.offset(self.len()),
1716+
VecMutIterator{ptr: p,
1717+
end: cast::transmute(p as uint + self.len() *
1718+
sys::nonzero_size_of::<T>()),
17161719
lifetime: cast::transmute(p)}
17171720
}
17181721
}
@@ -2089,7 +2092,11 @@ macro_rules! iterator {
20892092
None
20902093
} else {
20912094
let old = self.ptr;
2092-
self.ptr = self.ptr.offset(1);
2095+
// purposefully don't use 'ptr.offset' because for
2096+
// vectors with 0-size elements this would return the
2097+
// same pointer.
2098+
self.ptr = cast::transmute(self.ptr as uint +
2099+
sys::nonzero_size_of::<T>());
20932100
Some(cast::transmute(old))
20942101
}
20952102
}
@@ -2098,7 +2105,7 @@ macro_rules! iterator {
20982105
#[inline]
20992106
fn size_hint(&self) -> (uint, Option<uint>) {
21002107
let diff = (self.end as uint) - (self.ptr as uint);
2101-
let exact = diff / size_of::<$elem>();
2108+
let exact = diff / sys::nonzero_size_of::<$elem>();
21022109
(exact, Some(exact))
21032110
}
21042111
}
@@ -2115,7 +2122,9 @@ macro_rules! double_ended_iterator {
21152122
if self.end == self.ptr {
21162123
None
21172124
} else {
2118-
self.end = self.end.offset(-1);
2125+
// See above for why 'ptr.offset' isn't used
2126+
self.end = cast::transmute(self.end as uint -
2127+
sys::nonzero_size_of::<T>());
21192128
Some(cast::transmute(self.end))
21202129
}
21212130
}
@@ -2671,19 +2680,19 @@ mod tests {
26712680
let mut results: ~[~[int]];
26722681

26732682
results = ~[];
2674-
for each_permutation([]) |v| { results.push(to_owned(v)); }
2683+
for each_permutation([]) |v| { results.push(v.to_owned()); }
26752684
assert_eq!(results, ~[~[]]);
26762685

26772686
results = ~[];
2678-
for each_permutation([7]) |v| { results.push(to_owned(v)); }
2687+
for each_permutation([7]) |v| { results.push(v.to_owned()); }
26792688
assert_eq!(results, ~[~[7]]);
26802689

26812690
results = ~[];
2682-
for each_permutation([1,1]) |v| { results.push(to_owned(v)); }
2691+
for each_permutation([1,1]) |v| { results.push(v.to_owned()); }
26832692
assert_eq!(results, ~[~[1,1],~[1,1]]);
26842693

26852694
results = ~[];
2686-
for each_permutation([5,2,0]) |v| { results.push(to_owned(v)); }
2695+
for each_permutation([5,2,0]) |v| { results.push(v.to_owned()); }
26872696
assert!(results ==
26882697
~[~[5,2,0],~[5,0,2],~[2,5,0],~[2,0,5],~[0,5,2],~[0,2,5]]);
26892698
}
@@ -3370,4 +3379,50 @@ mod tests {
33703379

33713380
assert_eq!(values, [2, 3, 5, 6, 7]);
33723381
}
3382+
3383+
#[deriving(Eq)]
3384+
struct Foo;
3385+
3386+
#[test]
3387+
fn test_iter_zero_sized() {
3388+
let mut v = ~[Foo, Foo, Foo];
3389+
assert_eq!(v.len(), 3);
3390+
let mut cnt = 0;
3391+
3392+
for v.iter().advance |f| {
3393+
assert!(*f == Foo);
3394+
cnt += 1;
3395+
}
3396+
assert_eq!(cnt, 3);
3397+
3398+
for v.slice(1, 3).iter().advance |f| {
3399+
assert!(*f == Foo);
3400+
cnt += 1;
3401+
}
3402+
assert_eq!(cnt, 5);
3403+
3404+
for v.mut_iter().advance |f| {
3405+
assert!(*f == Foo);
3406+
cnt += 1;
3407+
}
3408+
assert_eq!(cnt, 8);
3409+
3410+
for v.consume_iter().advance |f| {
3411+
assert!(f == Foo);
3412+
cnt += 1;
3413+
}
3414+
assert_eq!(cnt, 11);
3415+
3416+
let xs = ~[Foo, Foo, Foo];
3417+
assert_eq!(fmt!("%?", xs.slice(0, 2).to_owned()), ~"~[{}, {}]");
3418+
3419+
let xs: [Foo, ..3] = [Foo, Foo, Foo];
3420+
assert_eq!(fmt!("%?", xs.slice(0, 2).to_owned()), ~"~[{}, {}]");
3421+
cnt = 0;
3422+
for xs.iter().advance |f| {
3423+
assert!(*f == Foo);
3424+
cnt += 1;
3425+
}
3426+
assert!(cnt == 3);
3427+
}
33733428
}

0 commit comments

Comments
 (0)