Skip to main content

ab_contracts_common/
output.rs

1//! Memory given to method calls as `#[output]`
2
3use crate::ContractError;
4use ab_io_type::maybe_data::MaybeData;
5use ab_io_type::trivial_type::{AnyBitPattern, TrivialType};
6use ab_io_type::variable_elements::VariableElements;
7use ab_io_type::{IoType, IoTypeMut};
8use core::marker::PhantomData;
9use core::mem::MaybeUninit;
10use core::ptr::NonNull;
11use core::{fmt, mem, ptr};
12
13/// Memory that can be given to a method call as an `#[output]` of type `Target`.
14///
15/// A call can leave contents behind that are not a valid value of `Target`, for example when it
16/// fails halfway, so the contents must be parsed before they are accessed, unless every bit
17/// pattern is a valid value (see [`AnyBitPattern`]). [`Lent`] does this for memory whose contents
18/// need parsing.
19///
20/// A call gets the pointer, size and capacity from [`Self::as_raw_output()`]. Until `self` is used
21/// again, the call may write initialized bytes anywhere within the capacity, even if it fails. If
22/// it succeeds, the size it reports is set with [`Self::set_output_size()`].
23///
24/// # Safety
25/// [`Self::as_raw_output()`] returns a pointer aligned for `Target::PointerType`, and a size that
26/// is valid for `Target` and doesn't exceed the capacity it returns. The pointer is valid for
27/// writes of the capacity, but for reads only of the size, with that many bytes initialized: the
28/// bytes after them may be uninitialized and must not be read before they are written. While
29/// `self` stays exclusively borrowed after that, the memory is not accessed other than through the
30/// pointer. Whatever initialized bytes a call leaves within the size (the initial one or the last
31/// one set with [`Self::set_output_size()`]) are never accessed as `Target` without being parsed
32/// first, unless every bit pattern is a valid value of `Target::PointerType`.
33#[diagnostic::on_unimplemented(
34    message = "`{Self}` can't be given to a call as an `#[output]` of type `{Target}`",
35    label = "expected `&mut {Target}` (or a view of one) whose contents accept every bit pattern, \
36    or `&mut Lent<{Target}>`",
37    note = "a failed call can leave invalid contents behind, use `Lent::new()` for a local value, \
38    `Lent::<MaybeData<_>>::from_uninit()` or `Lent::<VariableElements<_>>::from_uninit()` for a \
39    local container, or `Env::lend_output()` for an `#[output]` the method received"
40)]
41pub unsafe trait OutputArg<Target>
42where
43    Target: IoType,
44{
45    /// Pointer to the contents, size and capacity to give to a call
46    fn as_raw_output(&mut self) -> (NonNull<Target::PointerType>, u32, u32);
47
48    /// Set the size that a successful call reported.
49    ///
50    /// # Safety
51    /// `size` must be valid for `Target` (see [`IoType::try_from_ptr()`]) and not exceed the
52    /// capacity, and that many bytes must be initialized.
53    unsafe fn set_output_size(&mut self, size: u32);
54}
55
56// Without this attribute rustc reports the unsatisfied `AnyBitPattern` bound of the contents of
57// containers instead of the message of `OutputArg`
58#[diagnostic::do_not_recommend]
59// SAFETY: Pointer, size and capacity are those of a valid value, the pointer can be used for reads
60// of the size and writes of the capacity while the value isn't accessed otherwise
61// (`IoType::as_mut_ptr()`). The value is returned unchanged by every call of `io_type_mut()` and is
62// only accessible through `self` (`IoTypeMut` contract), so it isn't accessed while `self` is
63// exclusively borrowed. Initialized contents are a valid value, since every bit pattern is.
64unsafe impl<Arg> OutputArg<Arg::Target> for Arg
65where
66    Arg: IoTypeMut,
67    <Arg::Target as IoType>::PointerType: AnyBitPattern,
68{
69    #[inline(always)]
70    fn as_raw_output(&mut self) -> (NonNull<<Arg::Target as IoType>::PointerType>, u32, u32) {
71        let value = self.io_type_mut();
72        (
73            IoType::as_mut_ptr(value),
74            IoType::size(value),
75            IoType::capacity(value),
76        )
77    }
78
79    #[inline(always)]
80    unsafe fn set_output_size(&mut self, size: u32) {
81        // SAFETY: The size is valid and doesn't exceed the capacity, with that many bytes
82        // initialized (function contract), which are a valid value, since every bit pattern is
83        unsafe { IoType::set_size(self.io_type_mut(), size) }
84    }
85}
86
87enum LentValue<'a, T> {
88    /// A plain value owned by `Lent`, which may not be a valid value after a call
89    Owned(MaybeUninit<T>),
90    /// A container view owned by `Lent` over memory borrowed for `'a`. The view itself is valid,
91    /// while its contents may not be after a call.
92    View(T, PhantomData<&'a mut ()>),
93    /// A plain value or a container view borrowed for `'a`
94    Borrowed(NonNull<T>, PhantomData<&'a mut T>),
95}
96
97/// Memory lent to calls as an `#[output]`, whose contents are parsed before they are accessed.
98///
99/// A call can leave contents behind that are not a valid value, for example when it fails halfway,
100/// so the contents are only accessible through [`Self::get_mut()`], which parses them once after
101/// each call. Plain values can also be replaced with [`Self::set()`]. Memory whose contents accept
102/// every bit pattern can be given to calls directly, see [`OutputArg`].
103///
104/// Created with [`Self::new()`] for a local value, with `Lent::<MaybeData<_>>::from_uninit()` or
105/// `Lent::<VariableElements<_>>::from_uninit()` for a local container, and with
106/// [`Env::lend_output()`] for an `#[output]` the method received.
107///
108/// [`Env::lend_output()`]: crate::env::Env::lend_output
109pub struct Lent<'a, T>
110where
111    T: IoType,
112{
113    value: LentValue<'a, T>,
114    /// Pointer to the contents, size and capacity, read from the value again while it is
115    /// `checked`
116    ptr: NonNull<T::PointerType>,
117    size: u32,
118    capacity: u32,
119    /// Neither a call nor a size set changed the contents since they were last known to be valid
120    checked: bool,
121}
122
123impl<T> fmt::Debug for Lent<'_, T>
124where
125    T: IoType,
126{
127    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128        // Contents may not be a valid value
129        f.debug_struct("Lent")
130            .field("size", &self.size)
131            .field("capacity", &self.capacity)
132            .field("checked", &self.checked)
133            .finish_non_exhaustive()
134    }
135}
136
137// SAFETY: Pointer, size and capacity are those of the value when it was last known to be valid
138// (created, parsed or set), so the pointer can be used for reads of the size and writes of the
139// capacity (`IoType::as_mut_ptr()`). Since then, only calls changed the contents, by writing
140// initialized bytes within the capacity, and the size, through `Self::set_output_size()`. The value
141// is owned by `self` or borrowed by it for `'a`, so it isn't accessed while `self` is exclusively
142// borrowed. The contents are only accessed as `T` after `Self::get_mut()` parsed them or
143// `Self::set()` wrote a valid value.
144unsafe impl<T> OutputArg<T> for Lent<'_, T>
145where
146    T: IoType,
147{
148    #[inline(always)]
149    fn as_raw_output(&mut self) -> (NonNull<T::PointerType>, u32, u32) {
150        let raw_parts = self.raw_parts();
151        self.checked = false;
152        raw_parts
153    }
154
155    #[inline(always)]
156    unsafe fn set_output_size(&mut self, size: u32) {
157        // Make sure the cached size is that of the value
158        self.raw_parts();
159        // The only valid size of a plain value is its size, so a different size means `T` is a
160        // container view, which is a valid value regardless of its contents
161        if size != self.size {
162            // SAFETY: A container view, which is valid, owned by `self` or borrowed by it, and not
163            // referenced elsewhere while `self` is exclusively borrowed
164            let value = unsafe { self.value_ptr().as_mut() };
165            // SAFETY: The size is valid and doesn't exceed the capacity, with that many bytes
166            // initialized (function contract), the contents are only accessed after
167            // `Self::get_mut()` parsed them
168            unsafe {
169                IoType::set_size(value, size);
170            }
171            self.size = size;
172        }
173        // The contents may have changed together with the size
174        self.checked = false;
175    }
176}
177
178impl<T> Lent<'static, T>
179where
180    T: TrivialType,
181{
182    /// Lend a local value
183    #[inline(always)]
184    pub fn new(value: T) -> Self {
185        Self {
186            value: LentValue::Owned(MaybeUninit::new(value)),
187            // Read from the value before it is given to a call
188            ptr: NonNull::dangling(),
189            size: T::SIZE,
190            capacity: T::SIZE,
191            checked: true,
192        }
193    }
194}
195
196impl<'a, Data> Lent<'a, MaybeData<Data>>
197where
198    Data: TrivialType,
199    MaybeData<Data>: IoType,
200{
201    /// Lend a local [`MaybeData`] over uninitialized memory, like [`MaybeData::from_uninit()`].
202    ///
203    /// Returns `None` if `size != 0`.
204    #[inline(always)]
205    pub fn from_uninit(uninit: &'a mut MaybeUninit<Data>, size: &'a mut u32) -> Option<Self> {
206        let mut wrapper = MaybeData::from_uninit(uninit, size)?;
207        // SAFETY: The wrapper owns the view, which isn't accessible other than through the wrapper
208        // and stays valid without it (`IoTypeMut` contract). The wrapper is forgotten right after
209        // the view is moved out of it, so it never uses the view again, while `'a` of the returned
210        // `Lent` keeps the memory the view describes borrowed, like the wrapper did.
211        let view = unsafe { ptr::read(wrapper.io_type_mut()) };
212        mem::forget(wrapper);
213        Some(Self::from_view(view))
214    }
215}
216
217impl<'a, Element, const RECOMMENDED_ALLOCATION: u32>
218    Lent<'a, VariableElements<Element, RECOMMENDED_ALLOCATION>>
219where
220    Element: TrivialType,
221    VariableElements<Element, RECOMMENDED_ALLOCATION>: IoType,
222{
223    /// Lend a local [`VariableElements`] over uninitialized memory, like
224    /// [`VariableElements::from_uninit()`].
225    ///
226    /// Returns `None` if `size != 0` or if the buffer is larger than `u32::MAX` bytes.
227    #[inline(always)]
228    pub fn from_uninit(uninit: &'a mut [MaybeUninit<Element>], size: &'a mut u32) -> Option<Self> {
229        let mut wrapper =
230            VariableElements::<Element, RECOMMENDED_ALLOCATION>::from_uninit(uninit, size)?;
231        // SAFETY: The wrapper owns the view, which isn't accessible other than through the wrapper
232        // and stays valid without it (`IoTypeMut` contract). The wrapper is forgotten right after
233        // the view is moved out of it, so it never uses the view again, while `'a` of the returned
234        // `Lent` keeps the memory the view describes borrowed, like the wrapper did.
235        let view = unsafe { ptr::read(wrapper.io_type_mut()) };
236        mem::forget(wrapper);
237        Some(Self::from_view(view))
238    }
239}
240
241impl<'a, T> Lent<'a, T>
242where
243    T: IoType,
244{
245    /// Lend a container view over memory borrowed for `'a`
246    #[inline(always)]
247    fn from_view(mut view: T) -> Self {
248        let ptr = IoType::as_mut_ptr(&mut view);
249        let size = IoType::size(&view);
250        let capacity = IoType::capacity(&view);
251        Self {
252            value: LentValue::View(view, PhantomData),
253            ptr,
254            size,
255            capacity,
256            checked: true,
257        }
258    }
259
260    /// Lend `value`, which is only borrowed for `'a`, rather than until the method returns like
261    /// with [`Env::lend_output()`].
262    ///
263    /// # Safety
264    /// After the returned `Lent` was given to a call, `value` may hold contents that are not a
265    /// valid value. Once the `Lent` is no longer used, the contents of `value` must not be accessed
266    /// without being parsed first, unless the last use of the `Lent` after its last call was a
267    /// successful [`Self::get_mut()`] or [`Self::set()`], or the contents of `T` accept every bit
268    /// pattern.
269    ///
270    /// [`Env::lend_output()`]: crate::env::Env::lend_output
271    #[inline(always)]
272    pub unsafe fn from_mut_unchecked(value: &'a mut T) -> Self {
273        let ptr = IoType::as_mut_ptr(value);
274        let size = IoType::size(value);
275        let capacity = IoType::capacity(value);
276        Self {
277            value: LentValue::Borrowed(NonNull::from_mut(value), PhantomData),
278            ptr,
279            size,
280            capacity,
281            checked: true,
282        }
283    }
284
285    /// Exclusive access to the contents, which are parsed once after each call.
286    ///
287    /// Repeated calls without a call in between don't parse the contents again. Returns
288    /// [`ContractError::BadOutput`] if they are not a valid value of `T`. They then stay
289    /// inaccessible until [`Self::set()`], which only exists for plain values, replaces them.
290    /// Lending them again doesn't help either: methods generated by `#[contract]` reject outputs
291    /// with invalid initial contents with [`ContractError::BadInput`].
292    #[inline(always)]
293    pub fn get_mut(&mut self) -> Result<&mut T, ContractError> {
294        if !self.checked {
295            let (mut ptr, mut size, capacity) = self.raw_parts();
296            // SAFETY: The pointer is aligned and valid for writes of the capacity and for reads of
297            // the size, which is valid for `T` and doesn't exceed the capacity, with that many
298            // bytes initialized. The value was valid with these parts, and calls since then only
299            // wrote initialized bytes within the capacity and set a valid size
300            // (`OutputArg::set_output_size()` contract). Nothing else accesses the memory while
301            // `self` is exclusively borrowed, and the returned view is dropped right away.
302            if unsafe { T::try_from_mut_ptr(&mut ptr, &mut size, capacity) }.is_none() {
303                return Err(ContractError::BadOutput);
304            }
305            self.checked = true;
306        }
307        // SAFETY: A valid value, since it was parsed above or neither a call nor a size set changed
308        // it since it was last known to be valid, owned by `self` or borrowed by it, and not
309        // referenced elsewhere while `self` is borrowed
310        Ok(unsafe { self.value_ptr().as_mut() })
311    }
312
313    /// Pointer to the value, which may not be valid unless `checked`
314    #[inline(always)]
315    fn value_ptr(&mut self) -> NonNull<T> {
316        match &mut self.value {
317            LentValue::Owned(value) => NonNull::from_mut(value).cast::<T>(),
318            LentValue::View(view, _) => NonNull::from_mut(view),
319            LentValue::Borrowed(value, _) => *value,
320        }
321    }
322
323    /// Pointer to the contents, size and capacity, read from the value unless a call or a size set
324    /// may have changed it since it was last known to be valid
325    #[inline(always)]
326    fn raw_parts(&mut self) -> (NonNull<T::PointerType>, u32, u32) {
327        if self.checked {
328            // SAFETY: A valid value, since neither a call nor a size set changed it since it was
329            // created, parsed or set, owned by `self` or borrowed by it, and not referenced
330            // elsewhere while `self` is exclusively borrowed
331            let value = unsafe { self.value_ptr().as_mut() };
332            self.ptr = IoType::as_mut_ptr(value);
333            self.size = IoType::size(value);
334            self.capacity = IoType::capacity(value);
335        } else if let LentValue::Owned(value) = &mut self.value {
336            // An owned value moves together with `Lent`, unlike the memory of other values
337            self.ptr = NonNull::from_mut(value).cast::<T::PointerType>();
338        }
339        (self.ptr, self.size, self.capacity)
340    }
341}
342
343impl<T> Lent<'_, T>
344where
345    T: TrivialType,
346{
347    /// Replace the contents with a valid value
348    #[inline(always)]
349    pub fn set(&mut self, value: T) -> &mut T {
350        let mut ptr = self.value_ptr();
351        // SAFETY: Aligned and valid for writes of `T`, owned by `self` or borrowed by it, and not
352        // referenced elsewhere while `self` is exclusively borrowed
353        unsafe {
354            ptr.write(value);
355        }
356        self.checked = true;
357        // SAFETY: A valid value was written above, not referenced elsewhere while `self` is
358        // borrowed
359        unsafe { ptr.as_mut() }
360    }
361}