blob: 079daa47696b6773021cdbd901a7a5db20d40211 [file] [log] [blame]
// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#![feature(allocator_api)]
#![feature(cfg_sanitize)]
use std::collections::TryReserveError;
#[cfg(sanitize = "address")]
use std::ffi::c_void;
use std::mem::ManuallyDrop;
use std::ops::RangeBounds;
use std::ops::{Deref, DerefMut};
use std::ops::{Index, IndexMut};
use std::slice;
extern "C" {
// https://github.com/llvm/llvm-project/blob/9d0616ce52fc2a75c8e4808adec41d5189f4240c/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h#L70
#[cfg(sanitize = "address")]
fn __sanitizer_annotate_contiguous_container(
beg: *const c_void,
end: *const c_void,
old_mid: *const c_void,
new_mid: *const c_void,
);
}
/// A mutable, contiguous, dynamically-sized container of elements of type `T`,
/// ABI-compatible with `std::vector` from C++.
/// This layout was found empirically on Linux with modern g++ and libc++. If
/// for some version of libc++ it is different, we will need to update it with
/// conditional compilation.
#[repr(C)]
pub struct Vector<T> {
// TODO(b/356221873): Ensure Vector<T> is covariant.
begin: *mut T,
end: *mut T,
capacity_end: *mut T,
}
// TODO(b/356221873): Implement Send and Sync.
impl<T> Vector<T> {
pub fn new() -> Vector<T> {
Vector {
begin: core::ptr::null_mut(),
end: core::ptr::null_mut(),
capacity_end: core::ptr::null_mut(),
}
}
pub fn len(&self) -> usize {
// TODO(b/356221873): delete the `if` once a stable Rust release allows
// offset_from for "the same address"
if self.begin.is_null() {
0
} else {
unsafe { self.end.offset_from(self.begin).try_into().unwrap() }
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn capacity(&self) -> usize {
// TODO(b/356221873): delete the `if` once a stable Rust release allows
// offset_from for "the same address"
if self.begin.is_null() {
0
} else {
unsafe { self.capacity_end.offset_from(self.begin).try_into().unwrap() }
}
}
/// Prepares the vector to write into the tail.
/// See docstring of [`Vector::set_len`] for more details.
pub fn prepare_to_write_into_tail(&mut self) {
self.asan_unpoison_tail();
}
/// Sets the length of the vector.
///
/// # Safety
///
/// - `new_len` must be less than or equal to [`capacity()`].
/// - The elements at `old_len..new_len` must be initialized.
///
/// See [`std::vec::Vec::set_len`] for more details.
///
/// The difference with `std::vec::Vec::set_len` is that the tail of the
/// Vector is poisoned with ASan, so when writing to the tail for
/// avoiding ASan errors [`Vector::prepare_to_write_into_tail`] must be
/// called first:
/// ```
/// v.prepare_to_write_into_tail()
/// // write to tail (i.e. between v.len() and v.capacity())
/// v.set_len(len)
/// ```
pub unsafe fn set_len(&mut self, len: usize) {
self.end = self.begin.add(len);
self.asan_poison_tail();
}
#[inline]
#[cfg(not(sanitize = "address"))]
fn asan_poison_tail(&self) {}
#[inline]
#[cfg(not(sanitize = "address"))]
fn asan_unpoison_tail(&self) {}
#[inline]
#[cfg(sanitize = "address")]
fn asan_poison_tail(&self) {
// C++ std::vector supports an ASan container annotation feature
// (https://github.com/google/sanitizers/wiki/AddressSanitizerContainerOverflow)
// that allows ASan to detect reads and writes in the uninitialized tail of the
// std::vector's storage (between the end iterator and capacity).
//
// Rust std::vec::Vec intentionally does not support this ASan annotation
// feature, because it allows users to initialize the elements in the
// tail of the storage and then call set_len to tell the Vec about new
// elements.
//
// ASan uses the term "poisoned" for data that cannot be accessed. When marking
// data as inaccessible, we poison it, to make them accessible we
// unpoison the data. So, the tail of a Rust Vec's storage is always
// unpoisoned, even when ASan is enabled.
//
// Thus, when we use Rust Vec to implement operations on C++ std::vector's
// storage, we hit an incompatibility: the tail of the C++ std::vector
// is poisoned, but Rust Vec does not unpoison before writing into it.
//
// Therefore, when we create a Rust Vec using the storage of a C++ std::vector
// we need to establish the ASan poision/unpoison invariants that the Rust Vec
// expects. Specifically, we unpoison the storage before a Rust Vec
// writes into the uninitialized tail. Furthermore, once we are done
// using a Rust Vec to manipulate the storage, we poison the tail agail.
//
// As an optimization we don't poison/unpoison the tail when we create a Rust
// Vec purely to perform reads, or to mutate existing elements in-place.
unsafe {
// The following call is the same as __annotate_new in C++ std::vector
// https://github.com/llvm/llvm-project/blob/9d0616ce52fc2a75c8e4808adec41d5189f4240c/libcxx/include/vector#L920
__sanitizer_annotate_contiguous_container(
self.begin as *const c_void,
self.capacity_end as *const c_void,
self.capacity_end as *const c_void,
self.end as *const c_void,
);
}
}
#[inline]
#[cfg(sanitize = "address")]
fn asan_unpoison_tail(&self) {
unsafe {
// The following call is the same as __annotate_delete in C++
// std::vector https://github.com/llvm/llvm-project/blob/9d0616ce52fc2a75c8e4808adec41d5189f4240c/libcxx/include/vector#L927
__sanitizer_annotate_contiguous_container(
self.begin as *const c_void,
self.capacity_end as *const c_void,
self.end as *const c_void,
self.capacity_end as *const c_void,
);
}
}
}
impl<T: Unpin> Vector<T> {
/// Mutates `self` as if it were a `Vec<T>`.
fn mutate_self_as_vec<F, R>(&mut self, mutate_self: F) -> R
where
F: FnOnce(&mut Vec<T, cpp_std_allocator::StdAllocator>) -> R,
{
unsafe {
self.asan_unpoison_tail();
let mut v = ManuallyDrop::new(create_vec_from_raw_parts(
self.begin,
self.len(),
self.capacity(),
));
let result = mutate_self(v.deref_mut());
self.begin = v.as_mut_ptr();
self.end = self.begin.add(v.len());
self.capacity_end = self.begin.add(v.capacity());
self.asan_poison_tail();
result
}
}
// Methods for changing the capacity of the vector.
pub fn reserve(&mut self, capacity: usize) {
self.mutate_self_as_vec(|v| v.reserve(capacity));
}
pub fn reserve_exact(&mut self, additional: usize) {
self.mutate_self_as_vec(|v| v.reserve_exact(additional));
}
pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
self.mutate_self_as_vec(|v| v.try_reserve(additional))
}
pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
self.mutate_self_as_vec(|v| v.try_reserve_exact(additional))
}
pub fn shrink_to_fit(&mut self) {
self.mutate_self_as_vec(|v| v.shrink_to_fit());
}
pub fn shrink_to(&mut self, min_capacity: usize) {
self.mutate_self_as_vec(|v| v.shrink_to(min_capacity));
}
pub fn with_capacity(capacity: usize) -> Vector<T> {
let mut result = Vector::new();
result.reserve(capacity);
result
}
// Methods for adding elements to the vector.
pub fn push(&mut self, value: T) {
self.mutate_self_as_vec(|v| v.push(value));
}
pub fn insert(&mut self, index: usize, element: T) {
self.mutate_self_as_vec(|v| v.insert(index, element));
}
pub fn append(&mut self, other: &mut Self) {
self.mutate_self_as_vec(|v| other.mutate_self_as_vec(|other_v| v.append(other_v)))
}
// Methods for deleting elements from the vector.
pub fn swap_remove(&mut self, index: usize) -> T {
self.mutate_self_as_vec(|v| v.swap_remove(index))
}
pub fn remove(&mut self, index: usize) -> T {
self.mutate_self_as_vec(|v| v.remove(index))
}
pub fn pop(&mut self) -> Option<T> {
self.mutate_self_as_vec(|v| v.pop())
}
pub fn clear(&mut self) {
self.mutate_self_as_vec(|v| v.clear());
}
pub fn truncate(&mut self, len: usize) {
self.mutate_self_as_vec(|v| v.truncate(len));
}
// Different Vector transformations.
pub fn dedup_by<F>(&mut self, same_bucket: F)
where
F: FnMut(&mut T, &mut T) -> bool,
{
self.mutate_self_as_vec(|v| v.dedup_by(same_bucket));
}
pub fn dedup_by_key<F, K>(&mut self, key: F)
where
F: FnMut(&mut T) -> K,
K: PartialEq,
{
self.mutate_self_as_vec(|v| v.dedup_by_key(key));
}
// Methods returning different vector representations.
pub fn into_vec(mut self) -> Vec<T> {
let mut result = Vec::<T>::with_capacity(self.len());
unsafe {
std::ptr::copy_nonoverlapping(self.as_ptr(), result.as_mut_ptr(), self.len());
result.set_len(self.len());
// The elements were moved out. Now mark `self` empty, without calling drop on
// elements.
self.asan_unpoison_tail();
self.set_len(0);
}
result
}
pub fn as_ptr(&self) -> *const T {
self.begin
}
pub fn as_mut_ptr(&mut self) -> *mut T {
self.begin
}
pub fn as_slice(&self) -> &[T] {
unsafe { std::slice::from_raw_parts(self.begin, self.len()) }
}
pub fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { std::slice::from_raw_parts_mut(self.begin, self.len()) }
}
}
impl<T: Unpin + Clone> Vector<T> {
pub fn extend_from_within<R>(&mut self, src: R)
where
R: RangeBounds<usize>,
{
self.mutate_self_as_vec(|v| v.extend_from_within(src));
}
pub fn resize(&mut self, new_len: usize, value: T) {
self.mutate_self_as_vec(|v| v.resize(new_len, value));
}
pub fn resize_with<F>(&mut self, new_len: usize, f: F)
where
F: FnMut() -> T,
{
self.mutate_self_as_vec(|v| v.resize_with(new_len, f));
}
}
impl<T: Unpin + PartialEq> Vector<T> {
pub fn dedup(&mut self) {
self.mutate_self_as_vec(|v| v.dedup());
}
}
impl<T> Default for Vector<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> Drop for Vector<T> {
fn drop(&mut self) {
if !self.begin.is_null() {
unsafe {
self.asan_unpoison_tail();
_ = Vec::from_raw_parts_in(
self.begin,
self.len(),
self.capacity(),
cpp_std_allocator::StdAllocator {},
);
}
}
}
}
impl<T> Index<usize> for Vector<T> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
self.get(index).unwrap()
}
}
impl<T: Unpin> IndexMut<usize> for Vector<T> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.get_mut(index).unwrap()
}
}
impl<T> Deref for Vector<T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
if self.is_empty() {
&[]
} else {
unsafe { std::slice::from_raw_parts(self.begin, self.len()) }
}
}
}
impl<T: Unpin> DerefMut for Vector<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
if self.is_empty() {
&mut []
} else {
unsafe { std::slice::from_raw_parts_mut(self.begin, self.len()) }
}
}
}
impl<T: Unpin> From<Vec<T>> for Vector<T> {
fn from(v: Vec<T>) -> Self {
// Elements from `v` are moved. It would be more efficient to steal a buffer
// from `v`. But `v` might have different allocator than Vector.
// TODO(b/356221873): Figure out conditions when it is possible to steal buffer
// from `v`.
let mut result = Vector::<T>::with_capacity(v.len());
result.mutate_self_as_vec(|u| {
u.extend(v);
});
result
}
}
impl<T: Clone> Vector<T> {
/// Clone elements from `self` to `Vec<T>`.
pub fn to_vec(&self) -> Vec<T> {
let mut v = Vec::<T>::with_capacity(self.len());
for el in self.iter() {
v.push(el.clone());
}
v
}
}
impl<T: Unpin> Extend<T> for Vector<T> {
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = T>,
{
self.mutate_self_as_vec(|v| v.extend(iter));
}
}
/// Helper method for creating a `Vec<T>` from raw parts.
fn create_vec_from_raw_parts<T>(
begin: *mut T,
len: usize,
capacity: usize,
) -> Vec<T, cpp_std_allocator::StdAllocator> {
unsafe {
if begin.is_null() {
Vec::new_in(cpp_std_allocator::StdAllocator {})
} else {
Vec::from_raw_parts_in(begin, len, capacity, cpp_std_allocator::StdAllocator {})
}
}
}
mod iter {
use crate::Vector;
use std::fmt;
use std::fmt::Debug;
use std::iter::FusedIterator;
/// An iterator that moves out of a vector.
///
/// This type is currently a wrapper around `std::vec::IntoIter`,
/// however users should not depend on it, and the wrapped iterator
/// should not be made public. If the current implementation
/// strategy stops working, the wrapped iterator will be replaced with
/// a more complex implementation.
pub struct VectorIntoIter<T>(std::vec::IntoIter<T, cpp_std_allocator::StdAllocator>);
impl<T> VectorIntoIter<T> {
pub fn new(v: std::vec::IntoIter<T, cpp_std_allocator::StdAllocator>) -> Self {
VectorIntoIter(v)
}
/// Returns the remaining items of this iterator as a slice.
#[inline]
pub fn as_slice(&mut self) -> &[T] {
self.0.as_slice()
}
/// Returns the remaining items of this iterator as a mutable slice.
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [T] {
self.0.as_mut_slice()
}
}
impl<T> Iterator for VectorIntoIter<T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
// TODO(b/356638830): Uncomment when feature advance_by is stable
// fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
// self.0.advance_by(n)
// }
#[inline]
fn count(self) -> usize {
self.0.len()
}
}
impl<T> AsRef<[T]> for VectorIntoIter<T> {
fn as_ref(&self) -> &[T] {
self.0.as_ref()
}
}
impl<T: fmt::Debug> Debug for VectorIntoIter<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl<T: Unpin> Default for VectorIntoIter<T> {
fn default() -> Self {
Vector::<T>::default().into_iter()
}
}
impl<T> DoubleEndedIterator for VectorIntoIter<T> {
#[inline]
fn next_back(&mut self) -> Option<T> {
self.0.next_back()
}
// TODO(b/356638830): Uncomment when feature advance_back_by is stable
// #[inline]
// fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
// self.0.advance_back_by()
// }
}
impl<T> ExactSizeIterator for VectorIntoIter<T> {
// TODO(b/356638830): Uncomment when feature is_empty is stable
// #[inline]
// fn is_empty(&self) -> bool {
// self.0.is_empty()
// }
}
impl<T> FusedIterator for VectorIntoIter<T> {}
// TODO(b/356638830): Uncomment when feature TrustedLen is stable
// unsafe impl<T> TrustedLen for VectorIntoIter<T> {}
}
use iter::*;
impl<T: Unpin> IntoIterator for Vector<T> {
type Item = T;
type IntoIter = VectorIntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
unsafe {
self.asan_unpoison_tail();
let v = create_vec_from_raw_parts(self.begin, self.len(), self.capacity());
core::mem::forget(self);
VectorIntoIter::new(v.into_iter())
}
}
}
impl<'a, T: Unpin> IntoIterator for &'a Vector<T> {
type Item = &'a T;
type IntoIter = slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T: Unpin> IntoIterator for &'a mut Vector<T> {
type Item = &'a mut T;
type IntoIter = slice::IterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
impl<T: Unpin> FromIterator<T> for Vector<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let mut v = Self::new();
v.mutate_self_as_vec(|u| {
u.extend(iter);
});
v
}
}
impl<T: Unpin> From<Vector<T>> for std::vec::Vec<T> {
fn from(v: Vector<T>) -> std::vec::Vec<T> {
v.into_vec()
}
}