diff options
author | SoniEx2 <endermoneymod@gmail.com> | 2022-12-05 16:32:20 -0300 |
---|---|---|
committer | SoniEx2 <endermoneymod@gmail.com> | 2022-12-05 16:32:20 -0300 |
commit | 72841de072c4a904983e9eb631b690a61d3e06ff (patch) | |
tree | 18b5677a9bcc61e77a140b9012c1d82333e2f4f1 | |
parent | 2b5d0cb87b13fd5354143bb0b802d06ca0715ca6 (diff) |
Use closures for new_with
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | src/lib.rs | 101 | ||||
-rw-r--r-- | tests/ui/no_uaf_1.rs | 18 | ||||
-rw-r--r-- | tests/ui/no_uaf_1.stderr | 47 | ||||
-rw-r--r-- | tests/ui/no_uaf_2.rs | 4 |
5 files changed, 58 insertions, 114 deletions
diff --git a/Cargo.toml b/Cargo.toml index 672d5d7..6e8453c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "selfref" -version = "0.3.0" +version = "0.4.0" authors = ["SoniEx2 <endermoneymod@gmail.com>"] edition = "2021" description = "Semi-pain-free self-referential pinned types" diff --git a/src/lib.rs b/src/lib.rs index e87784d..fdefe7d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -84,7 +84,6 @@ //! # use std::cell::Cell; //! # //! use selfref::Holder; -//! use selfref::new_with_closure; //! # use selfref::opaque; //! # //! # struct MySelfRefStruct<'this> { @@ -102,7 +101,7 @@ //! fn main() { //! // first, construct the struct //! let holder = Box::pin(Holder::<'_, MySelfRefStructKey>::new_with( -//! new_with_closure::<MySelfRefStructKey, _>(|_| { +//! |foo| foo.build({ //! MySelfRefStruct { //! this: Cell::new(None) //! } @@ -131,7 +130,6 @@ //! use core::pin::pin; //! //! use selfref::Holder; -//! use selfref::NewWith; //! use selfref::opaque; //! //! struct Foo<'a, 'b: 'a> { @@ -147,23 +145,17 @@ //! } //! //! fn main() { -//! // can't use real closure, "hand-roll" a closure. -//! struct FooBuilder<'b>(&'b str); -//! impl<'k, 'b: 'k> NewWith<'k, FooKey<'b>> for FooBuilder<'b> { -//! fn new_with<'a>(self) -> Foo<'a, 'b> where 'k: 'a { -//! Foo { -//! foo: Default::default(), -//! t: self.0, -//! } -//! } -//! } -//! //! // a non-'static &str //! let stack_array: [u8; 5] = *b"hello"; //! let stack_str = core::str::from_utf8(&stack_array).unwrap(); //! //! // construct the struct -//! let holder = pin!(Holder::new_with(FooBuilder(stack_str))); +//! let holder = pin!(Holder::<'_, FooKey<'_>>::new_with(|foo| { +//! foo.build(Foo { +//! foo: Default::default(), +//! t: stack_str, +//! }) +//! })); //! //! holder.as_ref().operate_in(|foo| { //! foo.foo.set(Some(foo.get_ref())); @@ -427,7 +419,6 @@ macro_rules! opaque { /// use core::cell::Cell; /// /// use selfref::Holder; -/// use selfref::new_with_closure; /// use selfref::opaque; /// /// #[derive(Default)] @@ -445,7 +436,7 @@ macro_rules! opaque { /// fn main() { /// // We can use a closure here, but we need to give the compiler a hint. /// let holder = Holder::<'_, FooKey>::new_with( -/// new_with_closure::<FooKey, _>(|foo| Foo::default()) +/// |foo| foo.build(Foo::default()) /// ); /// } /// ``` @@ -454,36 +445,23 @@ pub struct Holder<'k, T> where T: Opaque + 'k { inner: <T as Opaque>::Kind<'k>, } -/// Helper trait for creating a [`Holder`]. +/// Helper for creating a [`Holder`]. /// /// This is necessary because closures don't work properly here. /// /// See [`Holder::new_with`] for examples. -pub trait NewWith<'k, T: Opaque + 'k> { - /// Creates a new `T::Kind` with an unbound lifetime. - fn new_with<'a>(self) -> T::Kind<'a> where 'k: 'a, T::Kind<'a>: Sized; +pub struct Builder<'k, T: Opaque + 'k> where T::Kind<'k>: Sized { + inner: Option<T::Kind<'k>>, } -impl<'k, T: Opaque + 'k, F> NewWith<'k, T> for F -where - F: for<'a> FnOnce([&'a (); 0]) -> <T as Opaque>::Kind<'a>, -{ - fn new_with<'a>(self) -> T::Kind<'a> where 'k: 'a, T::Kind<'a>: Sized { - self([]) +impl<'k, T: Opaque + 'k> Builder<'k, T> where T::Kind<'k>: Sized { + /// Builds the [`Holder`]. + #[inline] + pub fn build(&mut self, t: T::Kind<'k>) { + self.inner = Some(t); } } -/// Helper for creating a [`Holder`] using a closure. -/// -/// This only works if `K` is `'static`. -pub fn new_with_closure<K: Opaque, F>(f: F) -> F -where - F: for<'a> FnOnce([&'a (); 0]) -> <K as Opaque>::Kind<'a>, - for<'a> K::Kind<'a>: Sized, -{ - f -} - impl<'k, T> Holder<'k, T> where T: Opaque { /// Creates a new holder. /// @@ -495,7 +473,6 @@ impl<'k, T> Holder<'k, T> where T: Opaque { /// use core::cell::Cell; /// /// use selfref::Holder; - /// use selfref::new_with_closure; /// use selfref::opaque; /// /// #[derive(Default)] @@ -513,7 +490,7 @@ impl<'k, T> Holder<'k, T> where T: Opaque { /// fn main() { /// // We can use a closure here, but we need to help the compiler. /// let holder = Holder::<'_, FooKey>::new_with( - /// new_with_closure::<FooKey, _>(|foo| Foo::default()) + /// |foo| foo.build(Foo::default()) /// ); /// } /// ``` @@ -525,7 +502,6 @@ impl<'k, T> Holder<'k, T> where T: Opaque { /// use core::marker::PhantomData; /// /// use selfref::Holder; - /// use selfref::NewWith; /// use selfref::opaque; /// /// struct Foo<'a, 'b: 'a> { @@ -541,28 +517,27 @@ impl<'k, T> Holder<'k, T> where T: Opaque { /// } /// /// fn main() { - /// struct FooBuilder<'b>(&'b str); - /// impl<'k, 'b: 'k> NewWith<'k, FooKey<'b>> for FooBuilder<'b> { - /// fn new_with<'a>(self) -> Foo<'a, 'b> where 'k: 'a { - /// Foo { - /// foo: Default::default(), - /// t: self.0, - /// } - /// } - /// } /// let stack_array: [u8; 5] = *b"hello"; /// // a non-'static &str /// let stack_str = core::str::from_utf8(&stack_array).unwrap(); - /// let holder = Holder::new_with(FooBuilder(stack_str)); + /// let holder = Holder::<'_, FooKey<'_>>::new_with(|foo| { + /// foo.build(Foo { + /// foo: Default::default(), + /// t: stack_str, + /// }); + /// }); /// } /// ``` pub fn new_with<F>(f: F) -> Self where - F: NewWith<'k, T>, T::Kind<'k>: Sized + F: for<'a> FnOnce(&mut Builder<'a, T>), + T::Kind<'k>: Sized, { + let mut builder = Builder { inner: None }; + f(&mut builder); Self { // it is important that the constructor cannot observe 'k! - inner: f.new_with(), + inner: builder.inner.unwrap(), _pinned: PhantomPinned } } @@ -600,7 +575,6 @@ impl<'k, T> Holder<'k, T> where T: Opaque { /// use core::pin::pin; /// /// use selfref::Holder; - /// use selfref::new_with_closure; /// use selfref::opaque; /// /// #[derive(Default)] @@ -617,7 +591,7 @@ impl<'k, T> Holder<'k, T> where T: Opaque { /// /// fn main() { /// let holder = pin!(Holder::<'_, FooKey>::new_with( - /// new_with_closure::<FooKey, _>(|foo| Foo::default()) + /// |foo| foo.build(Foo::default()) /// )); /// // Actually making our Foo refer to itself. /// holder.as_ref().operate_in( @@ -639,7 +613,6 @@ impl<'k, T> Holder<'k, T> where T: Opaque { /// use core::pin::pin; /// /// use selfref::Holder; - /// use selfref::NewWith; /// use selfref::opaque; /// /// struct Foo<'a, 'b: 'a> { @@ -655,19 +628,15 @@ impl<'k, T> Holder<'k, T> where T: Opaque { /// } /// /// fn main() { - /// struct FooBuilder<'b>(&'b str); - /// impl<'k, 'b: 'k> NewWith<'k, FooKey<'b>> for FooBuilder<'b> { - /// fn new_with<'a>(self) -> Foo<'a, 'b> where 'k: 'a { - /// Foo { - /// foo: Default::default(), - /// t: self.0, - /// } - /// } - /// } /// let stack_array: [u8; 5] = *b"hello"; /// // a non-'static &str /// let stack_str = core::str::from_utf8(&stack_array).unwrap(); - /// let holder = pin!(Holder::new_with(FooBuilder(stack_str))); + /// let holder = pin!(Holder::<'_, FooKey<'_>>::new_with(|foo| { + /// foo.build(Foo { + /// foo: Default::default(), + /// t: stack_str, + /// }); + /// })); /// // Actually making our Foo refer to itself. /// holder.as_ref().operate_in(|foo| { /// foo.foo.set(Some(foo.get_ref())); diff --git a/tests/ui/no_uaf_1.rs b/tests/ui/no_uaf_1.rs index e4d7ac4..1d9411e 100644 --- a/tests/ui/no_uaf_1.rs +++ b/tests/ui/no_uaf_1.rs @@ -1,7 +1,6 @@ use core::cell::Cell; use selfref::Holder; -use selfref::NewWith; use selfref::opaque; mod bad { @@ -19,16 +18,13 @@ mod bad { } pub fn test() { let rc = Rc::new(Cell::new("")); - struct FooBuilder<'b>(Rc<Cell<&'b str>>); - impl<'k, 'b> NewWith<'k, FooOpaque> for FooBuilder<'b> { - fn new_with<'a>(self) -> Foo<'a> where 'k: 'a { - Foo { - x: "Hello".to_owned(), - y: self.0, - } - } - } - let x = Holder::new_with(FooBuilder(rc.clone())); + let rc_clone = rc.clone(); + let x = Holder::<'_, FooOpaque>::new_with(move |builder| { + builder.build(Foo { + x: "Hello".to_owned(), + y: rc_clone, + }); + }); let x = Box::pin(x); x.as_ref().operate_in(|foo| { let foo = foo.get_ref(); diff --git a/tests/ui/no_uaf_1.stderr b/tests/ui/no_uaf_1.stderr index 6db82ed..af0d3e6 100644 --- a/tests/ui/no_uaf_1.stderr +++ b/tests/ui/no_uaf_1.stderr @@ -1,37 +1,16 @@ -error: lifetime may not live long enough - --> tests/ui/no_uaf_1.rs:25:17 +error[E0521]: borrowed data escapes outside of closure + --> tests/ui/no_uaf_1.rs:23:13 | -23 | impl<'k, 'b> NewWith<'k, FooOpaque> for FooBuilder<'b> { - | -- lifetime `'b` defined here -24 | fn new_with<'a>(self) -> Foo<'a> where 'k: 'a { - | -- lifetime `'a` defined here -25 | / Foo { -26 | | x: "Hello".to_owned(), -27 | | y: self.0, -28 | | } - | |_________________^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` +21 | let rc_clone = rc.clone(); + | -------- `rc_clone` declared here, outside of the closure body +22 | let x = Holder::<'_, FooOpaque>::new_with(move |builder| { + | ------- `builder` is a reference that is only valid in the closure body +23 | / builder.build(Foo { +24 | | x: "Hello".to_owned(), +25 | | y: rc_clone, +26 | | }); + | |______________^ `builder` escapes the closure body here | - = help: consider adding the following bound: `'b: 'a` - = note: requirement occurs because of the type `Foo<'_>`, which makes the generic argument `'_` invariant - = note: the struct `Foo<'a>` is invariant over the parameter `'a` + = note: requirement occurs because of a mutable reference to `selfref::Builder<'_, FooOpaque>` + = note: mutable references are invariant over their type parameter = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance - -error: lifetime may not live long enough - --> tests/ui/no_uaf_1.rs:25:17 - | -23 | impl<'k, 'b> NewWith<'k, FooOpaque> for FooBuilder<'b> { - | -- lifetime `'b` defined here -24 | fn new_with<'a>(self) -> Foo<'a> where 'k: 'a { - | -- lifetime `'a` defined here -25 | / Foo { -26 | | x: "Hello".to_owned(), -27 | | y: self.0, -28 | | } - | |_________________^ associated function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` - | - = help: consider adding the following bound: `'a: 'b` - = note: requirement occurs because of the type `Foo<'_>`, which makes the generic argument `'_` invariant - = note: the struct `Foo<'a>` is invariant over the parameter `'a` - = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance - -help: `'b` and `'a` must be the same: replace one with the other diff --git a/tests/ui/no_uaf_2.rs b/tests/ui/no_uaf_2.rs index eb6b7d3..49694b2 100644 --- a/tests/ui/no_uaf_2.rs +++ b/tests/ui/no_uaf_2.rs @@ -6,7 +6,7 @@ use std::cell::Cell; use std::pin::pin; use selfref::opaque; -use selfref::{new_with_closure, Holder}; +use selfref::Holder; struct MyStruct<'this> { cell: Cell<&'this str>, @@ -22,7 +22,7 @@ opaque! { fn main() { let s = - Holder::<'_, MyStructKey>::new_with(new_with_closure::<MyStructKey, _>(|[]| MyStruct { + Holder::<'_, MyStructKey>::new_with(|builder| builder.build(MyStruct { cell: Default::default(), })); let s = pin!(s); |