1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
//! Convenient ways to shoot yourself in the foot. #![feature(alloc_layout_extra, maybe_uninit)] /// Given any pointer, even an immutable one with a short lifetime, returns a /// mutable pointer of unbounded `'static` lifetime to the same underlying /// address. /// /// # Safety /// /// "Abandon all hope, ye who enter here." /// /// ## Safe Alternative /// /// Declare an /// <code>[Rc](std::rc::Rc)<[RefCell](std::cell::RefCell)<T>></code> /// in your main or somewhere else near the bottom of your stack, and pass /// that around. /// /// # Example /// /// Interwoven use of two aliased mutable references: /// /// ``` /// let mut original = vec![1, 2, 3, 4, 5]; /// let handle = unsafe { fuckit::grapple(&original) }; /// original[4] = 1; /// handle[0] = 5; /// original[3] = 2; /// handle[1] = 4; /// assert_eq!(original, vec![5, 4, 3, 2, 1]); /// assert_eq!(original, *handle); /// ``` pub unsafe fn grapple<T>(pointer: &T) -> &'static mut T { #[allow( mutable_transmutes, clippy::transmute_ptr_to_ptr, clippy::clone_double_ref )] std::mem::transmute(pointer.clone()) } /// Given a statically-sized value, allocates new memory for it which will /// never be freed and moves (or copies) the value to that memory, where it /// will have an unbounded `'static` lifetime, and returns a mutable /// reference. This leaks memory. /// /// # Example /// /// Returning a reference to a locally-created value without manually making /// it owned by some longer-lived value. /// /// ``` /// fn inner_function() -> &'static mut Vec<usize> { /// let on_stack = vec![1, 2, 3]; /// let on_heap = fuckit::immortalize(on_stack); /// on_heap /// } /// /// let v = inner_function(); /// /// assert_eq!(*v, vec![1, 2, 3]); /// ``` pub fn immortalize<T>(value: T) -> &'static mut T { let reference = unsafe { summon() }; *reference = value; reference } /// Allocates space for a slice of `len` clones/copies of `value`, which will /// never be freed, so they can have unbounded `'static` lifetimes. This /// leaks memory. /// /// # Example /// /// Returning a reference to a locally-created slice of clones without /// manually making it owned by some longer-lived value. /// /// ``` /// fn inner_function() -> &'static mut [Vec<usize>] { /// let on_stack = vec![1, 2, 3]; /// let on_heap = fuckit::summon_clones(&on_stack, 32); /// on_heap /// } /// /// let vs = inner_function(); /// /// // Ensure the value was actually cloned: /// for v in vs.iter() { /// assert_eq!(*v, vec![1, 2, 3]); /// } /// /// // Ensure the value wasn't just aliased: modifying one vec shouldn't /// // affect the others: /// vs[0][0] = 99; /// vs[1].clear(); /// assert_eq!(1, vs[2][0]); /// assert_eq!(1, vs[31][0]); /// pub fn summon_clones<T: Clone>(value: &T, len: usize) -> &'static mut [T] { let slice = unsafe { summon_many(len) }; for clone in slice.iter_mut() { *clone = value.clone(); } slice } /// Allocates (but does not initialize) space for a value of type `T` which /// will never be freed, so it can have a unbounded `'static` lifetime. This /// leaks memory. /// /// # Safety /// /// The value must be initialized before it is used. /// /// ## Safe Alternative /// /// Use [`immortalize`] to move an existing value into such an allocation, so /// you can't forget to initialize it. pub unsafe fn summon<T>() -> &'static mut T { &mut summon_many(1)[0] } /// Allocates (but does not initialize) space for a slice of `len` values of /// type `T` which will never be freed, so they can have unbounded `'static` /// lifetimes. This leaks memory. /// /// # Safety /// /// Each value must be initialized before it is used. /// /// ## Safe Alternative /// /// Use [`summon_clones`] to automatically initialize the values to /// clones/copies of a provided value. pub unsafe fn summon_many<T>(len: usize) -> &'static mut [T] { let layout = std::alloc::Layout::array::<T>(len).unwrap(); // Ask your allocator for the memory. let pointer: *mut u8 = std::alloc::alloc(layout); // As in C, we get a pointer to raw bytes, so we cast it. let typed_pointer = pointer as *mut T; // Then we return a slice pointing to the allocation. // A slcie is just a typed pointer with a length for bounds-checking. std::slice::from_raw_parts_mut(typed_pointer, len) }