Advertisement
Guest User

Untitled

a guest
May 24th, 2019
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.08 KB | None | 0 0
  1. #![allow(dead_code)]
  2.  
  3. use std::cell::RefCell;
  4. use std::cell::RefMut;
  5. use std::collections::HashMap;
  6. use std::marker::PhantomData;
  7. use std::mem;
  8. use std::sync::Mutex;
  9. use std::thread;
  10. use lazy_static::lazy_static;
  11.  
  12. // Jump to the examples at the end!
  13.  
  14. // The metadata we store is just a colour for each memory address.
  15. struct MetaData(Mutex<HashMap<Address, Colour>>);
  16.  
  17. lazy_static! { static ref METADATA: MetaData = MetaData(Mutex::new(HashMap::new())); }
  18.  
  19. // Memory addresses are just a word
  20. type Address = usize;
  21.  
  22. // The different states of memory
  23. #[derive(Clone, Copy, Debug, Eq, PartialEq)]
  24. enum Colour {
  25. Undefined, // Memory that has not been allocated
  26. Unreachable, // Memory that is allocated but can't be reached from safe code
  27. Unique, // Memory that is reachable from safe code as a &mut T reference
  28. Shared, // Memory that is reachable from safe code as a &T reference
  29. }
  30.  
  31.  
  32. // Types that can change colour.
  33. // For the whole language, every type would implement this,\
  34. // for now we just do tuples of integers.
  35. trait Colourable {
  36. fn colour(address: Address, from: Colour, to: Colour);
  37. }
  38.  
  39. impl Colourable for u8 {
  40. fn colour(address: Address, from: Colour, to: Colour) {
  41. let old = METADATA.0.lock().unwrap().insert(address, to).unwrap_or(Colour::Undefined);
  42. if !thread::panicking() && (from != old) {
  43. panic!("UB: Found colour {:?}, expecting {:?} at address 0x{:x}.", old, from, address);
  44. }
  45. }
  46. }
  47.  
  48. impl Colourable for u16 {
  49. fn colour(address: Address, from: Colour, to: Colour) {
  50. u8::colour(address, from, to);
  51. u8::colour(address + 1, from, to);
  52. }
  53. }
  54.  
  55. impl Colourable for u32 {
  56. fn colour(address: Address, from: Colour, to: Colour) {
  57. u16::colour(address, from, to);
  58. u16::colour(address + 2, from, to);
  59. }
  60. }
  61.  
  62. impl Colourable for u64 {
  63. fn colour(address: Address, from: Colour, to: Colour) {
  64. u32::colour(address, from, to);
  65. u32::colour(address + 4, from, to);
  66. }
  67. }
  68.  
  69. impl Colourable for usize {
  70. fn colour(address: Address, from: Colour, to: Colour) {
  71. u64::colour(address, from, to);
  72. }
  73. }
  74.  
  75. impl<T, U> Colourable for (T, U) where T: Colourable, U: Colourable {
  76. fn colour(address: Address, from: Colour, to: Colour) {
  77. T::colour(address, from, to);
  78. U::colour(address + mem::size_of::<T>(), from, to);
  79. }
  80. }
  81.  
  82. impl<T> Colourable for RefCell<T> where T: Colourable {
  83. fn colour(address: Address, from: Colour, to: Colour) {
  84. // This assumes that the address of the RefCell is not
  85. // the same as the address of the pointer in the RefCell.
  86. u8::colour(address, from, to);
  87. // Really we should be able to this without casting,
  88. // but the RefCell's fields are private.
  89. let refcell = unsafe { &*(address as *const RefCell<T>) };
  90. let address = refcell.as_ptr() as Address;
  91. if from == Colour::Undefined {
  92. T::colour(address, Colour::Undefined, Colour::Unreachable);
  93. } else if from == Colour::Undefined {
  94. T::colour(address, Colour::Unreachable, Colour::Undefined);
  95. }
  96. }
  97. }
  98.  
  99. // When we recolour memory, we leave a Recolour marker on the stack.
  100. // When its drop code runs, it undoes the recolouring.
  101. struct Recolour<T: Colourable> {
  102. old: Colour,
  103. new: Colour,
  104. address: Address,
  105. marker: PhantomData<T>,
  106. }
  107.  
  108. impl<T: Colourable> Drop for Recolour<T> {
  109. fn drop(&mut self) {
  110. T::colour(self.address, self.new, self.old);
  111. }
  112. }
  113.  
  114. // A trick to make sure the Recolour marker lasts as long as the borrow does
  115. impl<T: Colourable> Recolour<T> {
  116. fn set_address<'a>(&'a mut self, reference: &'a T) -> &'a T {
  117. self.address = reference as *const T as Address;
  118. T::colour(self.address, self.old, self.new);
  119. reference
  120. }
  121. fn set_address_mut<'a>(&'a mut self, reference: &'a mut T) -> &'a mut T {
  122. self.address = reference as *mut T as Address;
  123. T::colour(self.address, self.old, self.new);
  124. reference
  125. }
  126. }
  127.  
  128. // A macro for tracking borrows and reborrows.
  129. // This is my attempt to code the borrow model directly in Rust.
  130. macro_rules! track {
  131. // Borrow a T as a &mut T
  132. (let $x:ident : &mut $t:ty = &mut $e:expr) => {
  133. let mut tmp : $t = $e;
  134. let mut recolour = Recolour {
  135. old: Colour::Undefined,
  136. new: Colour::Unique,
  137. address: 0,
  138. marker: PhantomData,
  139. };
  140. let $x : &mut $t = recolour.set_address_mut(&mut tmp);
  141. };
  142. // Reborrow a &mut T as a &T
  143. (let $x:ident : & $t:ty = $e:expr) => {
  144. let tmp: &mut $t = $e;
  145. let mut recolour = Recolour {
  146. old: Colour::Unique,
  147. new: Colour::Shared,
  148. address: 0,
  149. marker: PhantomData,
  150. };
  151. let $x : & $t = recolour.set_address(tmp);
  152. };
  153. // Cast a *mut T to a &mut T
  154. (let $x:ident : &mut $t:ty = unsafe { &mut * ($e:expr) }) => {
  155. let tmp: *mut $t = $e;
  156. let mut recolour = Recolour {
  157. old: Colour::Unreachable,
  158. new: Colour::Unique,
  159. address: 0,
  160. marker: PhantomData,
  161. };
  162. let $x : &mut $t = recolour.set_address_mut(unsafe { &mut *tmp });
  163. };
  164. // Cast a *const T to a &T
  165. (let $x:ident : & $t:ty = unsafe { & * ($e:expr) }) => {
  166. let tmp: *const $t = $e;
  167. let mut recolour = Recolour {
  168. old: Colour::Shared,
  169. new: Colour::Shared,
  170. address: 0,
  171. marker: PhantomData,
  172. };
  173. let $x : & $t = recolour.set_address(unsafe { &*tmp });
  174. };
  175. // Cast a &mut T to a *mut T
  176. (let $x:ident : *mut $t:ty = $e:expr) => {
  177. let tmp: &mut $t = $e;
  178. let mut recolour = Recolour {
  179. old: Colour::Unique,
  180. new: Colour::Unreachable,
  181. address: 0,
  182. marker: PhantomData,
  183. };
  184. let $x : *mut $t = recolour.set_address_mut(tmp);
  185. };
  186. // Cast a &T to a *const T
  187. (let $x:ident : *const $t:ty = $e:expr) => {
  188. let tmp: & $t = $e;
  189. let mut recolour = Recolour {
  190. old: Colour::Shared,
  191. new: Colour::Shared,
  192. address: 0,
  193. marker: PhantomData,
  194. };
  195. let $x : *const $t = recolour.set_address(tmp);
  196. };
  197. // Borrow mutably from a RefCell
  198. (let mut $x:ident : RefMut<$t:ty> = $y:ident .borrow_mut()) => {
  199. let tmp: &RefCell<$t> = $y;
  200. let mut $x : RefMut<$t> = tmp.borrow_mut();
  201. <$t as Colourable>::colour(&*$x as *const $t as Address, Colour::Unreachable, Colour::Unique);
  202. };
  203. // Drop a mutable borrow from a RefCell
  204. (drop ($x:ident as RefMut<$t:ty>)) => {
  205. let tmp: RefMut<$t> = $x;
  206. <$t as Colourable>::colour(&*tmp as *const $t as Address, Colour::Unique, Colour::Unreachable);
  207. drop (tmp);
  208. };
  209.  
  210. // Casting between raw pointers doesn't require tracking
  211. }
  212.  
  213. // An example, showing how we can track metadata for how memory is being used
  214.  
  215. fn bad(p: &usize) {
  216. track!(let q : *const usize = p);
  217. track!(let r : &mut usize = unsafe { &mut *(q as *mut usize) });
  218. *r = 5;
  219. }
  220.  
  221. fn simple() {
  222. track!(let x : &mut usize = &mut 37);
  223. {
  224. track!(let y : &usize = x);
  225. bad(y);
  226. }
  227. *x += 1;
  228. print!("*x = {}", *x);
  229. }
  230.  
  231. // Another example, from Ralf Jung
  232.  
  233. fn aliasing_mut_and_shr() {
  234. fn inner(rc: &RefCell<u32>, aliasing: &mut u32) {
  235. *aliasing += 4;
  236. track!(let _escape_to_raw : *const RefCell<u32> = rc);
  237. *aliasing += 4;
  238. let _shr = &*rc;
  239. *aliasing += 4;
  240. // also turning this into a frozen ref now must work
  241. track!(let aliasing : &u32 = aliasing);
  242. let _val = *aliasing;
  243. track!(let _escape_to_raw : *const RefCell<u32> = rc);
  244. let _val = *aliasing;
  245. let _shr = &*rc; // this must NOT unfreeze
  246. let _val = *aliasing;
  247. }
  248.  
  249. let refcell = RefCell::new(23);
  250. track!(let rc: &mut RefCell<u32> = &mut refcell);
  251. track!(let rc: &RefCell<u32> = rc);
  252. track!(let mut bmut : RefMut<u32> = rc.borrow_mut());
  253. inner(&rc, &mut *bmut);
  254. track!(drop (bmut as RefMut<u32>));
  255. assert_eq!(*rc.borrow(), 23+12);
  256. }
  257.  
  258. fn main() {
  259. aliasing_mut_and_shr()
  260. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement