diff options
| author | bors <bors@rust-lang.org> | 2020-02-08 03:46:56 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2020-02-08 03:46:56 +0000 |
| commit | 6cad7542da2f10e2110f942de4db59716bacb3df (patch) | |
| tree | c3344ccc601a6bbdebd9b69ee1a92e4e81cfceac /src/libcore/ops | |
| parent | 8498c5f5b02dbb4ed58a1eb4901b0b733342c35f (diff) | |
| parent | a81c59f9b84b6519785a4e0ae9234107d149f454 (diff) | |
| download | rust-6cad7542da2f10e2110f942de4db59716bacb3df.tar.gz rust-6cad7542da2f10e2110f942de4db59716bacb3df.zip | |
Auto merge of #68358 - matthewjasper:spec-fix, r=nikomatsakis
Remove some unsound specializations This removes the unsound and exploitable specializations in the standard library * The `PartialEq` and `Hash` implementations for `RangeInclusive` are changed to avoid specialization. * The `PartialOrd` specialization for slices now specializes on a limited set of concrete types. * Added some tests for the soundness problems.
Diffstat (limited to 'src/libcore/ops')
| -rw-r--r-- | src/libcore/ops/range.rs | 38 |
1 files changed, 15 insertions, 23 deletions
diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index d38b3516569..6c0bc6bbbad 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -343,38 +343,21 @@ pub struct RangeInclusive<Idx> { pub(crate) is_empty: Option<bool>, // This field is: // - `None` when next() or next_back() was never called - // - `Some(false)` when `start <= end` assuming no overflow - // - `Some(true)` otherwise + // - `Some(false)` when `start < end` + // - `Some(true)` when `end < start` + // - `Some(false)` when `start == end` and the range hasn't yet completed iteration + // - `Some(true)` when `start == end` and the range has completed iteration // The field cannot be a simple `bool` because the `..=` constructor can // accept non-PartialOrd types, also we want the constructor to be const. } -trait RangeInclusiveEquality: Sized { - fn canonicalized_is_empty(range: &RangeInclusive<Self>) -> bool; -} - -impl<T> RangeInclusiveEquality for T { - #[inline] - default fn canonicalized_is_empty(range: &RangeInclusive<Self>) -> bool { - range.is_empty.unwrap_or_default() - } -} - -impl<T: PartialOrd> RangeInclusiveEquality for T { - #[inline] - fn canonicalized_is_empty(range: &RangeInclusive<Self>) -> bool { - range.is_empty() - } -} - #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: PartialEq> PartialEq for RangeInclusive<Idx> { #[inline] fn eq(&self, other: &Self) -> bool { self.start == other.start && self.end == other.end - && RangeInclusiveEquality::canonicalized_is_empty(self) - == RangeInclusiveEquality::canonicalized_is_empty(other) + && self.is_exhausted() == other.is_exhausted() } } @@ -386,7 +369,8 @@ impl<Idx: Hash> Hash for RangeInclusive<Idx> { fn hash<H: Hasher>(&self, state: &mut H) { self.start.hash(state); self.end.hash(state); - RangeInclusiveEquality::canonicalized_is_empty(self).hash(state); + // Ideally we would hash `is_exhausted` here as well, but there's no + // way for us to call it. } } @@ -485,6 +469,14 @@ impl<Idx: fmt::Debug> fmt::Debug for RangeInclusive<Idx> { } } +impl<Idx: PartialEq<Idx>> RangeInclusive<Idx> { + // Returns true if this is a range that started non-empty, and was iterated + // to exhaustion. + fn is_exhausted(&self) -> bool { + Some(true) == self.is_empty && self.start == self.end + } +} + impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> { /// Returns `true` if `item` is contained in the range. /// |
