Skip to main content

starnix_core/mm/
memory_accessor.rs

1// Copyright 2025 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::mm::PAGE_SIZE;
6use crate::vfs::{FsStr, FsString};
7use smallvec::SmallVec;
8use starnix_types::user_buffer::{UserBuffer, UserBuffers, UserBuffers32};
9use starnix_uapi::errors::Errno;
10use starnix_uapi::user_address::{
11    ArchSpecific, MappingMultiArchUserRef, MultiArchUserRef, UserAddress, UserAddress32,
12    UserCString, UserRef,
13};
14use starnix_uapi::user_value::UserValue;
15use starnix_uapi::{PATH_MAX, UIO_MAXIOV, errno, error, uapi};
16use std::ffi::CStr;
17use std::mem::MaybeUninit;
18use usercopy::slice_to_maybe_uninit_mut;
19use zerocopy::{FromBytes, Immutable, IntoBytes};
20
21pub type IOVecPtr = MultiArchUserRef<uapi::iovec, uapi::arch32::iovec>;
22
23pub trait MemoryAccessor {
24    /// Reads exactly `bytes.len()` bytes of memory from `addr` into `bytes`.
25    ///
26    /// In case of success, the number of bytes read will always be `bytes.len()`.
27    ///
28    /// Consider using `MemoryAccessorExt::read_memory_to_*` methods if you do not require control
29    /// over the allocation.
30    fn read_memory<'a>(
31        &self,
32        addr: UserAddress,
33        bytes: &'a mut [MaybeUninit<u8>],
34    ) -> Result<&'a mut [u8], Errno>;
35
36    /// Reads bytes starting at `addr`, continuing until either a null byte is read, `bytes.len()`
37    /// bytes have been read or no more bytes can be read from the target.
38    ///
39    /// This is used, for example, to read null-terminated strings where the exact length is not
40    /// known, only the maximum length is.
41    ///
42    /// Returns the bytes that have been read to on success.
43    fn read_memory_partial_until_null_byte<'a>(
44        &self,
45        addr: UserAddress,
46        bytes: &'a mut [MaybeUninit<u8>],
47    ) -> Result<&'a mut [u8], Errno>;
48
49    /// Reads bytes starting at `addr`, continuing until either `bytes.len()` bytes have been read
50    /// or no more bytes can be read from the target.
51    ///
52    /// This is used, for example, to read null-terminated strings where the exact length is not
53    /// known, only the maximum length is.
54    ///
55    /// Consider using `MemoryAccessorExt::read_memory_partial_to_*` methods if you do not require
56    /// control over the allocation.
57    fn read_memory_partial<'a>(
58        &self,
59        addr: UserAddress,
60        bytes: &'a mut [MaybeUninit<u8>],
61    ) -> Result<&'a mut [u8], Errno>;
62
63    /// Writes the provided bytes to `addr`.
64    ///
65    /// In case of success, the number of bytes written will always be `bytes.len()`.
66    ///
67    /// # Parameters
68    /// - `addr`: The address to write to.
69    /// - `bytes`: The bytes to write from.
70    fn write_memory(&self, addr: UserAddress, bytes: &[u8]) -> Result<usize, Errno>;
71
72    /// Writes bytes starting at `addr`, continuing until either `bytes.len()` bytes have been
73    /// written or no more bytes can be written.
74    ///
75    /// # Parameters
76    /// - `addr`: The address to write to.
77    /// - `bytes`: The bytes to write from.
78    fn write_memory_partial(&self, addr: UserAddress, bytes: &[u8]) -> Result<usize, Errno>;
79
80    /// Writes zeros starting at `addr` and continuing for `length` bytes.
81    ///
82    /// Returns the number of bytes that were zeroed.
83    fn zero(&self, addr: UserAddress, length: usize) -> Result<usize, Errno>;
84}
85
86/// Whether user-space memory is being accessed for reading or writing.
87#[derive(Clone, Copy, Debug, PartialEq, Eq)]
88pub enum MappingAccess {
89    ForReading,
90    ForWriting,
91}
92
93pub trait TaskMemoryAccessor: MemoryAccessor {
94    /// Returns the maximum valid address for this memory accessor.
95    fn maximum_valid_address(&self) -> Option<UserAddress>;
96
97    /// Ensures that any mappings in `buffers` are mapped in the user VMAR with the permissions
98    /// needed for `access`.
99    fn ensure_buffers_mapped_in_user_vmar(
100        &self,
101        buffers: &[UserBuffer],
102        access: MappingAccess,
103    ) -> Result<(), Errno>;
104}
105
106// TODO(https://fxbug.dev/42079727): replace this with MaybeUninit::as_bytes_mut.
107#[inline]
108fn object_as_mut_bytes<T: FromBytes + Sized>(
109    object: &mut MaybeUninit<T>,
110) -> &mut [MaybeUninit<u8>] {
111    // SAFETY: T is FromBytes, which means that any bit pattern is valid. Interpreting
112    // MaybeUninit<T> as [MaybeUninit<u8>] is safe because T's alignment requirements
113    // are larger than u8.
114    unsafe {
115        std::slice::from_raw_parts_mut(
116            object.as_mut_ptr() as *mut MaybeUninit<u8>,
117            std::mem::size_of::<T>(),
118        )
119    }
120}
121
122// TODO(https://fxbug.dev/42079727): replace this with MaybeUninit::slice_as_bytes_mut.
123#[inline]
124fn slice_as_mut_bytes<T: FromBytes + Sized>(
125    slice: &mut [MaybeUninit<T>],
126) -> &mut [MaybeUninit<u8>] {
127    // SAFETY: T is FromBytes, which means that any bit pattern is valid. Interpreting T as u8
128    // is safe because T's alignment requirements are larger than u8.
129    unsafe {
130        std::slice::from_raw_parts_mut(
131            slice.as_mut_ptr() as *mut MaybeUninit<u8>,
132            slice.len() * std::mem::size_of::<T>(),
133        )
134    }
135}
136
137/// Holds the number of _elements_ read by the callback to [`read_to_vec`].
138///
139/// Used to make it clear to callers that the callback should return the number
140/// of elements read and not the number of bytes read.
141pub struct NumberOfElementsRead(pub usize);
142
143/// Performs a read into a `Vec` using the provided read function.
144///
145/// The read function returns the number of elements of type `T` read.
146///
147/// # Safety
148///
149/// The read function must only return `Ok(n)` if at least one element was read and `n` holds
150/// the number of elements of type `T` read starting from the beginning of the slice.
151#[inline]
152pub unsafe fn read_to_vec<T: FromBytes, E>(
153    max_len: usize,
154    read_fn: impl FnOnce(&mut [MaybeUninit<T>]) -> Result<NumberOfElementsRead, E>,
155) -> Result<Vec<T>, E> {
156    let mut buffer = Vec::with_capacity(max_len);
157    // We can't just pass `spare_capacity_mut` because `Vec::with_capacity`
158    // returns a `Vec` with _at least_ the requested capacity.
159    let NumberOfElementsRead(read_elements) = read_fn(&mut buffer.spare_capacity_mut()[..max_len])?;
160    debug_assert!(read_elements <= max_len, "read_elements={read_elements}, max_len={max_len}");
161    // SAFETY: The new length is equal to the number of elements successfully
162    // initialized (since `read_fn` returned successfully).
163    unsafe { buffer.set_len(read_elements) }
164    Ok(buffer)
165}
166
167/// Performs a read into an array using the provided read function.
168///
169//
170/// The read function returns `Ok(())` if the buffer was fully read to.
171///
172/// # Safety
173///
174/// The read function must only return `Ok(())` if all the bytes were read to.
175#[inline]
176pub unsafe fn read_to_array<T: FromBytes, E, const N: usize>(
177    read_fn: impl FnOnce(&mut [MaybeUninit<T>]) -> Result<(), E>,
178) -> Result<[T; N], E> {
179    // TODO(https://fxbug.dev/129314): replace with MaybeUninit::uninit_array.
180    let buffer: MaybeUninit<[MaybeUninit<T>; N]> = MaybeUninit::uninit();
181    // SAFETY: We are converting from an uninitialized array to an array
182    // of uninitialized elements which is the same. See
183    // https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#initializing-an-array-element-by-element.
184    let mut buffer = unsafe { buffer.assume_init() };
185    read_fn(&mut buffer)?;
186    // SAFETY: This is safe because we have initialized all the elements in
187    // the array (since `read_fn` returned successfully).
188    //
189    // TODO(https://fxbug.deb/129309): replace with MaybeUninit::array_assume_init.
190    let buffer = buffer.map(|a| unsafe { a.assume_init() });
191    Ok(buffer)
192}
193
194/// Performs a read into an object using the provided read function.
195///
196/// The read function returns `Ok(())` if the buffer was fully read to.
197///
198/// # Safety
199///
200/// The read function must only return `Ok(())` if all the bytes were read to.
201#[inline]
202pub unsafe fn read_to_object_as_bytes<T: FromBytes, E>(
203    read_fn: impl FnOnce(&mut [MaybeUninit<u8>]) -> Result<(), E>,
204) -> Result<T, E> {
205    // Over-align the object to 8 bytes (a `T` with a larger alignment keeps it), the size of the
206    // words that `hermetic_copy` copies. When the user address is also 8-byte aligned, as it
207    // typically is for objects read from user memory, this lets every word access be aligned on
208    // both sides: arm64 aligns the user pointer and accesses the kernel buffer as is, and x64 and
209    // riscv64 only use their word loop when both pointers have the same alignment. A larger
210    // alignment would not change any access, since aligned 8-byte accesses never straddle a cache
211    // line.
212    #[repr(C, align(8))]
213    struct Aligned<T>(MaybeUninit<T>);
214    let mut object = Aligned(MaybeUninit::uninit());
215    read_fn(object_as_mut_bytes(&mut object.0))?;
216    // SAFETY: The call to `read_fn` succeeded so we know that `object`
217    // has been initialized.
218    let object = unsafe { object.0.assume_init() };
219    Ok(object)
220}
221
222pub trait MemoryAccessorExt: MemoryAccessor {
223    /// Reads exactly `bytes.len()` bytes of memory from `addr` into `bytes`.
224    ///
225    /// In case of success, the number of bytes read will always be `bytes.len()`.
226    ///
227    /// Consider using `MemoryAccessorExt::read_memory_to_*` methods if you do not require control
228    /// over the allocation.
229    fn read_memory_to_slice(&self, addr: UserAddress, bytes: &mut [u8]) -> Result<(), Errno> {
230        let bytes_len = bytes.len();
231        self.read_memory(addr, slice_to_maybe_uninit_mut(bytes))
232            .map(|bytes_read| debug_assert_eq!(bytes_read.len(), bytes_len))
233    }
234
235    /// Read exactly `len` bytes of memory, returning them as a a Vec.
236    fn read_memory_to_vec(&self, addr: UserAddress, len: usize) -> Result<Vec<u8>, Errno> {
237        // SAFETY: `self.read_memory` only returns `Ok` if all bytes were read to.
238        unsafe {
239            read_to_vec::<u8, _>(len, |buf| {
240                self.read_memory(addr, buf).map(|bytes_read| {
241                    debug_assert_eq!(bytes_read.len(), len);
242                    NumberOfElementsRead(len)
243                })
244            })
245        }
246    }
247
248    /// Read up to `max_len` bytes from `addr`, returning them as a Vec.
249    fn read_memory_partial_to_vec(
250        &self,
251        addr: UserAddress,
252        max_len: usize,
253    ) -> Result<Vec<u8>, Errno> {
254        // SAFETY: `self.read_memory_partial` returns the bytes read.
255        unsafe {
256            read_to_vec::<u8, _>(max_len, |buf| {
257                self.read_memory_partial(addr, buf)
258                    .map(|bytes_read| NumberOfElementsRead(bytes_read.len()))
259            })
260        }
261    }
262
263    /// Read exactly `N` bytes from `addr`, returning them as an array.
264    fn read_memory_to_array<const N: usize>(&self, addr: UserAddress) -> Result<[u8; N], Errno> {
265        // SAFETY: `self.read_memory` only returns `Ok` if all bytes were read to.
266        unsafe {
267            read_to_array(|buf| {
268                self.read_memory(addr, buf).map(|bytes_read| debug_assert_eq!(bytes_read.len(), N))
269            })
270        }
271    }
272
273    /// Read the contents of `buffer`, returning them as a Vec.
274    fn read_buffer(&self, buffer: &UserBuffer) -> Result<Vec<u8>, Errno> {
275        self.read_memory_to_vec(buffer.address, buffer.length)
276    }
277
278    /// Read an instance of T from `user`.
279    fn read_object<T: FromBytes>(&self, user: UserRef<T>) -> Result<T, Errno> {
280        // SAFETY: `self.read_memory` only returns `Ok` if all bytes were read to.
281        unsafe {
282            read_to_object_as_bytes(|buf| {
283                self.read_memory(user.addr(), buf)
284                    .map(|bytes_read| debug_assert_eq!(bytes_read.len(), std::mem::size_of::<T>()))
285            })
286        }
287    }
288
289    fn read_multi_arch_ptr<T64, T32>(
290        &self,
291        user: MultiArchUserRef<MultiArchUserRef<T64, T32>, MultiArchUserRef<T64, T32>>,
292    ) -> Result<MultiArchUserRef<T64, T32>, Errno> {
293        let address = if user.is_arch32() {
294            self.read_object::<UserAddress32>(user.addr().into())?.into()
295        } else {
296            self.read_object::<UserAddress>(user.addr().into())?
297        };
298        Ok(MultiArchUserRef::<T64, T32>::new(&user, address))
299    }
300
301    /// Read an instance of T64 from `user` where the object has a different representation in 32
302    /// and 64 bits.
303    fn read_multi_arch_object<T, T64: FromBytes + TryInto<T>, T32: FromBytes + TryInto<T>>(
304        &self,
305        user: MappingMultiArchUserRef<T, T64, T32>,
306    ) -> Result<T, Errno> {
307        match user {
308            MappingMultiArchUserRef::<T, T64, T32>::Arch64(user, _) => {
309                self.read_object(user)?.try_into().map_err(|_| errno!(EINVAL))
310            }
311            MappingMultiArchUserRef::<T, T64, T32>::Arch32(user) => {
312                self.read_object(user)?.try_into().map_err(|_| errno!(EINVAL))
313            }
314        }
315    }
316
317    /// Read exactly `len` objects from `user`, returning them as a Vec.
318    fn read_multi_arch_objects_to_vec<
319        T,
320        T64: FromBytes + TryInto<T>,
321        T32: FromBytes + TryInto<T>,
322    >(
323        &self,
324        user: MappingMultiArchUserRef<T, T64, T32>,
325        len: usize,
326    ) -> Result<Vec<T>, Errno> {
327        match user {
328            MappingMultiArchUserRef::<T, T64, T32>::Arch64(user, _) => self
329                .read_objects_to_vec(user, len)?
330                .into_iter()
331                .map(TryInto::<T>::try_into)
332                .collect::<Result<Vec<T>, _>>()
333                .map_err(|_| errno!(EINVAL)),
334            MappingMultiArchUserRef::<T, T64, T32>::Arch32(user) => self
335                .read_objects_to_vec(user, len)?
336                .into_iter()
337                .map(TryInto::<T>::try_into)
338                .collect::<Result<Vec<T>, _>>()
339                .map_err(|_| errno!(EINVAL)),
340        }
341    }
342
343    /// Reads the first `partial` bytes of an object, leaving any remainder 0-filled.
344    ///
345    /// This is used for reading size-versioned structures where the user can specify an older
346    /// version of the structure with a smaller size.
347    ///
348    /// Returns EINVAL if the input size is larger than the object (assuming the input size is from
349    /// the user who has specified something we don't support).
350    fn read_object_partial<T: FromBytes>(
351        &self,
352        user: UserRef<T>,
353        partial_size: usize,
354    ) -> Result<T, Errno> {
355        let full_size = std::mem::size_of::<T>();
356        if partial_size > full_size {
357            return error!(EINVAL);
358        }
359
360        // This implementation involves an extra memcpy compared to read_object but avoids unsafe
361        // code. This isn't currently called very often.
362        let mut object = MaybeUninit::uninit();
363        let (to_read, to_zero) = object_as_mut_bytes(&mut object).split_at_mut(partial_size);
364        self.read_memory(user.addr(), to_read)?;
365
366        // Zero pad out to the correct size.
367        to_zero.fill(MaybeUninit::new(0));
368
369        // SAFETY: `T` implements `FromBytes` so any bit pattern is valid and all
370        // bytes of `object` have been initialized.
371        Ok(unsafe { object.assume_init() })
372    }
373
374    /// Read exactly `objects.len()` objects into `objects` from `user`.
375    fn read_objects<'a, T: FromBytes>(
376        &self,
377        user: UserRef<T>,
378        objects: &'a mut [MaybeUninit<T>],
379    ) -> Result<&'a mut [T], Errno> {
380        let objects_len = objects.len();
381        self.read_memory(user.addr(), slice_as_mut_bytes(objects)).map(|bytes_read| {
382            debug_assert_eq!(bytes_read.len(), objects_len * std::mem::size_of::<T>());
383            // SAFETY: `T` implements `FromBytes` and all bytes have been initialized.
384            unsafe {
385                std::slice::from_raw_parts_mut(bytes_read.as_mut_ptr() as *mut T, objects_len)
386            }
387        })
388    }
389
390    /// Read exactly `objects.len()` objects into `objects` from `user`.
391    fn read_objects_to_slice<T: FromBytes>(
392        &self,
393        user: UserRef<T>,
394        objects: &mut [T],
395    ) -> Result<(), Errno> {
396        let objects_len = objects.len();
397        self.read_objects(user, slice_to_maybe_uninit_mut(objects))
398            .map(|objects_read| debug_assert_eq!(objects_read.len(), objects_len))
399    }
400
401    /// Read exactly `len` objects from `user`, returning them as a Vec.
402    fn read_objects_to_vec<T: FromBytes>(
403        &self,
404        user: UserRef<T>,
405        len: usize,
406    ) -> Result<Vec<T>, Errno> {
407        // SAFETY: `self.read_objects` only returns `Ok` if all bytes were read to.
408        unsafe {
409            read_to_vec::<T, _>(len, |buf| {
410                self.read_objects(user, buf).map(|objects_read| {
411                    debug_assert_eq!(objects_read.len(), len);
412                    NumberOfElementsRead(len)
413                })
414            })
415        }
416    }
417
418    /// Read exactly `len` objects from `user`, returning them as a SmallVec.
419    fn read_objects_to_smallvec<T: Clone + FromBytes, const N: usize>(
420        &self,
421        user: UserRef<T>,
422        len: usize,
423    ) -> Result<SmallVec<[T; N]>, Errno> {
424        if len > N {
425            Ok(SmallVec::<[T; N]>::from_vec(self.read_objects_to_vec(user, len)?))
426        } else {
427            let mut buffer: [MaybeUninit<T>; N] = [const { MaybeUninit::uninit() }; N];
428
429            self.read_objects(user, &mut buffer[..len])?;
430
431            // TODO(https://github.com/rust-lang/rust/issues/96097) use MaybeUninit::transpose
432            // SAFETY: MaybeUninit<[T; N]> and [MaybeUninit<T>; N] have the same layout.
433            let buffer: MaybeUninit<[T; N]> = unsafe { std::mem::transmute_copy(&buffer) };
434
435            // SAFETY: `read_objects` guarantees that the first `len` entries are initialized.
436            Ok(unsafe { SmallVec::from_buf_and_len_unchecked(buffer, len) })
437        }
438    }
439
440    /// Read exactly `N` objects from `user`, returning them as an array.
441    fn read_objects_to_array<T: Copy + FromBytes, const N: usize>(
442        &self,
443        user: UserRef<T>,
444    ) -> Result<[T; N], Errno> {
445        // SAFETY: `self.read_objects` only returns `Ok` if all bytes were read to.
446        unsafe {
447            read_to_array(|buf| {
448                self.read_objects(user, buf).map(|objects_read| {
449                    debug_assert_eq!(objects_read.len(), N);
450                })
451            })
452        }
453    }
454
455    /// Read exactly `iovec_count` `UserBuffer`s from `iovec_addr`.
456    ///
457    /// Fails if `iovec_count` is greater than `UIO_MAXIOV`.
458    fn read_iovec<T: Copy + Eq + IntoBytes + FromBytes + Immutable + TryInto<usize>>(
459        &self,
460        iovec_addr: IOVecPtr,
461        iovec_count: UserValue<T>,
462    ) -> Result<UserBuffers, Errno> {
463        let iovec_count = iovec_count.raw().try_into().map_err(|_| errno!(EINVAL))?;
464        if iovec_count > UIO_MAXIOV as usize {
465            return error!(EINVAL);
466        }
467
468        if iovec_addr.is_arch32() {
469            let ub32s: UserBuffers32 =
470                self.read_objects_to_smallvec(iovec_addr.addr().into(), iovec_count)?;
471            Ok(ub32s.iter().map(|&ub32| ub32.into()).collect())
472        } else {
473            self.read_objects_to_smallvec(iovec_addr.addr().into(), iovec_count)
474        }
475    }
476
477    /// Read up to `max_size` bytes from `string`, stopping at the first discovered null byte and
478    /// returning the results as a Vec.
479    fn read_c_string_to_vec(
480        &self,
481        string: UserCString,
482        max_size: usize,
483    ) -> Result<FsString, Errno> {
484        let chunk_size = std::cmp::min(*PAGE_SIZE as usize, max_size);
485
486        let mut buf = Vec::with_capacity(chunk_size);
487        let mut index = 0;
488        loop {
489            // This operation should never overflow: we should fail to read before that.
490            let addr = string.addr().checked_add(index).ok_or_else(|| errno!(EFAULT))?;
491            let read = self.read_memory_partial_until_null_byte(
492                addr,
493                &mut buf.spare_capacity_mut()[index..][..chunk_size],
494            )?;
495            let read_len = read.len();
496
497            // Check if the last byte read is the null byte.
498            if read.last() == Some(&0) {
499                let null_index = index + read_len - 1;
500                // SAFETY: Bytes until `null_index` have been initialized.
501                unsafe { buf.set_len(null_index) }
502                if buf.len() > max_size {
503                    return error!(ENAMETOOLONG);
504                }
505
506                return Ok(buf.into());
507            }
508            index += read_len;
509
510            if read_len < chunk_size || index >= max_size {
511                // There's no more for us to read.
512                return error!(ENAMETOOLONG);
513            }
514
515            // Trigger a capacity increase.
516            buf.reserve(index + chunk_size);
517        }
518    }
519
520    /// Read a path from `path`, returning it as a `FsString`.
521    ///
522    /// A convenience function that enforces the path length limit.
523    fn read_path(&self, path: UserCString) -> Result<FsString, Errno> {
524        self.read_c_string_to_vec(path, PATH_MAX as usize)
525    }
526
527    /// Read a path from `path`, returning it as a `FsString`, if the path is non-null.
528    ///
529    /// A convenience function that enforces the path length limit.
530    fn read_path_if_non_null(&self, path: UserCString) -> Result<FsString, Errno> {
531        if path.is_null() {
532            Ok(Default::default())
533        } else {
534            self.read_c_string_to_vec(path, PATH_MAX as usize)
535        }
536    }
537
538    /// Read `len` bytes from `start` and parse the region as null-delimited CStrings, for example
539    /// how `argv` is stored.
540    ///
541    /// There can be an arbitrary number of null bytes in between `start` and `end`.
542    fn read_nul_delimited_c_string_list(
543        &self,
544        start: UserAddress,
545        len: usize,
546    ) -> Result<Vec<FsString>, Errno> {
547        let buf = self.read_memory_to_vec(start, len)?;
548        let mut buf = &buf[..];
549
550        let mut list = vec![];
551        while !buf.is_empty() {
552            let len_consumed = match CStr::from_bytes_until_nul(buf) {
553                Ok(segment) => {
554                    // Return the string without the null to match our other APIs, but advance the
555                    // "cursor" of the buf variable past the null byte.
556                    list.push(segment.to_bytes().into());
557                    segment.to_bytes_with_nul().len()
558                }
559                Err(_) => {
560                    // If we didn't find a null byte, then the whole rest of the buffer is the
561                    // last string.
562                    list.push(buf.into());
563                    buf.len()
564                }
565            };
566            buf = &buf[len_consumed..];
567        }
568
569        Ok(list)
570    }
571
572    /// Read up to `buffer.len()` bytes from `string`, stopping at the first discovered null byte
573    /// and returning the result as a slice that ends before that null.
574    ///
575    /// Consider using `read_c_string_to_vec` if you do not require control over the allocation.
576    fn read_c_string<'a>(
577        &self,
578        string: UserCString,
579        buffer: &'a mut [MaybeUninit<u8>],
580    ) -> Result<&'a FsStr, Errno> {
581        let buffer = self.read_memory_partial_until_null_byte(string.addr(), buffer)?;
582        // Make sure the last element holds the null byte.
583        if let Some((null_byte, buffer)) = buffer.split_last() {
584            if null_byte == &0 {
585                return Ok(buffer.into());
586            }
587        }
588
589        error!(ENAMETOOLONG)
590    }
591
592    /// Returns a default initialized string if `addr` is null, otherwise
593    /// behaves as `read_c_string`.
594    fn read_c_string_if_non_null<'a>(
595        &self,
596        addr: UserCString,
597        buffer: &'a mut [MaybeUninit<u8>],
598    ) -> Result<&'a FsStr, Errno> {
599        if addr.is_null() { Ok(Default::default()) } else { self.read_c_string(addr, buffer) }
600    }
601
602    fn write_object<T: IntoBytes + Immutable>(
603        &self,
604        user: UserRef<T>,
605        object: &T,
606    ) -> Result<usize, Errno> {
607        self.write_memory(user.addr(), object.as_bytes())
608    }
609
610    fn write_objects<T: IntoBytes + Immutable>(
611        &self,
612        user: UserRef<T>,
613        objects: &[T],
614    ) -> Result<usize, Errno> {
615        self.write_memory(user.addr(), objects.as_bytes())
616    }
617
618    fn write_multi_arch_ptr<Addr, T64, T32>(
619        &self,
620        user: Addr,
621        object: MultiArchUserRef<T64, T32>,
622    ) -> Result<usize, Errno>
623    where
624        Addr: Into<UserAddress>,
625    {
626        if object.is_arch32() {
627            let value = u32::try_from(object.ptr()).map_err(|_| errno!(EINVAL))?;
628            self.write_memory(user.into(), value.as_bytes())
629        } else {
630            self.write_memory(user.into(), object.ptr().as_bytes())
631        }
632    }
633
634    fn write_multi_arch_object<
635        T,
636        T64: IntoBytes + Immutable + TryFrom<T>,
637        T32: IntoBytes + Immutable + TryFrom<T>,
638    >(
639        &self,
640        user: MappingMultiArchUserRef<T, T64, T32>,
641        object: T,
642    ) -> Result<usize, Errno> {
643        match user {
644            MappingMultiArchUserRef::<T, T64, T32>::Arch64(user, _) => {
645                self.write_object(user, &T64::try_from(object).map_err(|_| errno!(EINVAL))?)
646            }
647            MappingMultiArchUserRef::<T, T64, T32>::Arch32(user) => {
648                self.write_object(user, &T32::try_from(object).map_err(|_| errno!(EINVAL))?)
649            }
650        }
651    }
652}
653
654impl MemoryAccessorExt for dyn MemoryAccessor + '_ {}
655impl<T: MemoryAccessor> MemoryAccessorExt for T {}