Advertisement
Guest User

Untitled

a guest
Apr 25th, 2019
81
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.50 KB | None | 0 0
  1. #![feature(custom_attribute)]
  2. use std::fmt::{Result as FmtResult, Formatter, Debug};
  3. use std::alloc::{Layout, alloc, realloc, dealloc};
  4. use std::ptr::{read, write, drop_in_place};
  5. use std::mem::transmute;
  6.  
  7. /// A very unsafe vector whose elements are all `Option<T>`'s, where `T` is chosen with each `get`
  8. /// and `set` operation.
  9. ///
  10. /// TODO: This needs to be audited.
  11. struct UnsafeDynOptionVec {
  12. /// If `len != 0`, the address at which the allocated `Option<T>`'s start.
  13. ptr: *mut u8,
  14. /// The number of allocated `Option<T>`'s.
  15. len: usize,
  16. /// The layout of each `Option<T>`.
  17. layout: Layout,
  18. /// The destructor for `Option<T>`.
  19. dtor: unsafe fn(*mut u8),
  20. }
  21.  
  22. impl UnsafeDynOptionVec {
  23. /// Creates a new, empty `UnsafeDynOptionVec`.
  24. pub fn new<T: 'static>() -> UnsafeDynOptionVec {
  25. unsafe fn dtor<T>(ptr: *mut u8) {
  26. drop_in_place::<T>(ptr as *mut T)
  27. }
  28.  
  29. UnsafeDynOptionVec {
  30. ptr: 1 as _,
  31. len: 0,
  32. layout: Layout::new::<Option<T>>(),
  33. dtor: dtor::<Option<T>>,
  34. }
  35. }
  36.  
  37. /// Grows the vector to (at least) the given size.
  38. fn grow_to<T: 'static>(&mut self, mut n: usize) {
  39. if n < self.len {
  40. return;
  41. }
  42.  
  43. if let Some(new_n) = n.checked_next_power_of_two() {
  44. n = new_n;
  45. }
  46.  
  47. let new_layout = self.layout_with_len(n);
  48. let ptr = if self.len == 0 {
  49. unsafe { alloc(new_layout) }
  50. } else {
  51. unsafe { realloc(self.ptr, self.layout(), new_layout.size()) }
  52. };
  53.  
  54. if ptr.is_null() {
  55. // `self` is safe to drop. Either `alloc` failed, and `self.len` is therefore `0`, so
  56. // no `dealloc` will occur, or `realloc` failed, and `self.ptr` is still
  57. // `dealloc`atable.
  58. panic!("allocation failure in component store")
  59. }
  60.  
  61. let old_len = self.len;
  62. self.ptr = ptr;
  63. self.len = n;
  64.  
  65. for i in old_len..n {
  66. unsafe { write(self.ptr(i) as *mut Option<T>, None) };
  67. }
  68. }
  69.  
  70. /// Returns the current layout of the vector.
  71. fn layout(&self) -> Layout {
  72. // This is a good indication we've forgotten to check for an empty vector.
  73. debug_assert_ne!(self.len, 0);
  74.  
  75. self.layout_with_len(self.len)
  76. }
  77.  
  78. /// Returns the layout the vector would have if it were of length `n`.
  79. fn layout_with_len(&self, n: usize) -> Layout {
  80. // All the code here is copied from `libcore/alloc.rs.html`, but is unstable there. This
  81. // will just be
  82. //
  83. // ```rust
  84. // self.layout
  85. // .repeat(n)
  86. // .map(|(l, _)| l)
  87. // .expect("overflow in size of component store")
  88. // ```
  89. //
  90. // once that method is stable.
  91.  
  92. let align = self.layout.align();
  93. let size = self.layout.size();
  94. let size_rounded_up = size.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
  95. let alloc_size = size
  96. .checked_add(size_rounded_up.wrapping_sub(size))
  97. .and_then(|padded_size| padded_size.checked_mul(n));
  98.  
  99. if let Some(alloc_size) = alloc_size {
  100. unsafe { Layout::from_size_align_unchecked(alloc_size, align) }
  101. } else {
  102. panic!("overflow of size of component store")
  103. }
  104. }
  105.  
  106. /// Returns a pointer to the `n`th item of the vector.
  107. #[safety(assert(n < self.len), "`n` must be less than the allocated length of the vector")]
  108. unsafe fn ptr(&self, n: usize) -> *mut u8 {
  109. let size = self.layout_with_len(n).size();
  110. self.ptr.add(size)
  111. }
  112.  
  113. /// Reads the `n`th value from the `UnsafeDynOptionVec`. This will return `None` if the given
  114. /// index is out of bounds.
  115. #[safety(eq(self.layout, Layout::new::<Option<T>>()),
  116. "T must have the same layout as the type that was given to `UnsafeDynOptionVec::new`")]
  117. #[safety("T must be the same type as was given to `UnsafeDynOptionVec::new`")]
  118. pub unsafe fn get<T: 'static>(&self, n: usize) -> Option<&T> {
  119. if n > self.len {
  120. return None;
  121. }
  122. transmute::<*const Option<T>, &Option<T>>(self.ptr(n) as _).as_ref()
  123. }
  124.  
  125. /// Sets the `n`th value from the `UnsafeDynOptionVec` to `Some` value. This will extend the
  126. /// underlying allocation if `n` is out of bounds.
  127. #[safety(eq(self.layout, Layout::new::<Option<T>>()),
  128. "T must have the same layout as the type that was given to `UnsafeDynOptionVec::new`")]
  129. #[safety("T must be the same type as was given to `UnsafeDynOptionVec::new`")]
  130. pub unsafe fn set<T: 'static>(&mut self, n: usize, component: T) {
  131. self.grow_to::<T>(
  132. n.checked_add(1)
  133. .expect("overflow of size of component store"),
  134. );
  135. *(self.ptr(n) as *mut Option<T>) = None;
  136. }
  137.  
  138. /// Removes the `n`th value from the `UnsafeDynOptionVec`. This is a no-op if `n` is out of
  139. /// bounds.
  140. #[safety(eq(self.layout, Layout::new::<Option<T>>()),
  141. "T must have the same layout as the type that was given to `UnsafeDynOptionVec::new`")]
  142. #[safety("T must be the same type as was given to `UnsafeDynOptionVec::new`")]
  143. pub unsafe fn remove<T: 'static>(&mut self, n: usize) {
  144. if n >= self.len {
  145. return;
  146. }
  147. *(self.ptr(n) as *mut Option<T>) = None;
  148. }
  149. }
  150.  
  151. impl Debug for UnsafeDynOptionVec {
  152. fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
  153. fmt.debug_struct("UnsafeDynOptionVec").finish()
  154. }
  155. }
  156.  
  157. impl Drop for UnsafeDynOptionVec {
  158. fn drop(&mut self) {
  159. if self.len != 0 {
  160. for i in 0..self.len {
  161. unsafe { (self.dtor)(self.ptr(i)) }
  162. }
  163. unsafe { dealloc(self.ptr, self.layout()) }
  164. }
  165. }
  166. }
  167.  
  168. #[test]
  169. #[should_panic(expected = "boom")]
  170. fn no_double_drop() {
  171. use std::sync::atomic::{AtomicBool, Ordering};
  172. use lazy_static::lazy_static;
  173.  
  174. lazy_static! {
  175. static ref SHOULD_PANIC: AtomicBool = AtomicBool::new(false);
  176. }
  177. #[derive(Debug)]
  178. struct P(bool);
  179.  
  180. impl Drop for P {
  181. fn drop(&mut self) {
  182. if dbg!(self.0) {
  183. panic!("double-dropping!");
  184. }
  185. self.0 = true;
  186. if SHOULD_PANIC.load(Ordering::SeqCst) {
  187. SHOULD_PANIC.store(false, Ordering::SeqCst);
  188. panic!("boom");
  189. }
  190. }
  191. }
  192.  
  193. let mut store = UnsafeDynOptionVec::new::<P>();
  194. unsafe {
  195. store.set(0, P(false));
  196.  
  197. SHOULD_PANIC.store(true, Ordering::SeqCst);
  198. store.set(0, P(false));
  199. }
  200. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement