Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  allocator_test.rs   Sprache: unbekannt

 
// SPDX-License-Identifier: GPL-2.0

//! So far the kernel's `Box` and `Vec` types can't be used by userspace test cases, since all users
//! of those types (e.g. `CString`) use kernel allocators for instantiation.
//!
//! In order to allow userspace test cases to make use of such types as well, implement the
//! `Cmalloc` allocator within the `allocator_test` module and type alias all kernel allocators to
//! `Cmalloc`. The `Cmalloc` allocator uses libc's `realloc()` function as allocator backend.

#![allow(missing_docs)]

use super::{flags::*, AllocError, Allocator, Flags};
use core::alloc::Layout;
use core::cmp;
use core::ptr;
use core::ptr::NonNull;

/// The userspace allocator based on libc.
pub struct Cmalloc;

pub type Kmalloc = Cmalloc;
pub type Vmalloc = Kmalloc;
pub type KVmalloc = Kmalloc;

impl Cmalloc {
    /// Returns a [`Layout`] that makes [`Kmalloc`] fulfill the requested size and alignment of
    /// `layout`.
    pub fn aligned_layout(layout: Layout) -> Layout {
        // Note that `layout.size()` (after padding) is guaranteed to be a multiple of
        // `layout.align()` which together with the slab guarantees means that `Kmalloc` will return
        // a properly aligned object (see comments in `kmalloc()` for more information).
        layout.pad_to_align()
    }
}

extern "C" {
    #[link_name = "aligned_alloc"]
    fn libc_aligned_alloc(align: usize, size: usize) -> *mut crate::ffi::c_void;

    #[link_name = "free"]
    fn libc_free(ptr: *mut crate::ffi::c_void);
}

// SAFETY:
// - memory remains valid until it is explicitly freed,
// - passing a pointer to a valid memory allocation created by this `Allocator` is always OK,
// - `realloc` provides the guarantees as provided in the `# Guarantees` section.
unsafe impl Allocator for Cmalloc {
    unsafe fn realloc(
        ptr: Option<NonNull<u8>>,
        layout: Layout,
        old_layout: Layout,
        flags: Flags,
    ) -> Result<NonNull<[u8]>, AllocError> {
        let src = match ptr {
            Some(src) => {
                if old_layout.size() == 0 {
                    ptr::null_mut()
                } else {
                    src.as_ptr()
                }
            }
            None => ptr::null_mut(),
        };

        if layout.size() == 0 {
            // SAFETY: `src` is either NULL or was previously allocated with this `Allocator`
            unsafe { libc_free(src.cast()) };

            return Ok(NonNull::slice_from_raw_parts(
                crate::alloc::dangling_from_layout(layout),
                0,
            ));
        }

        // ISO C (ISO/IEC 9899:2011) defines `aligned_alloc`:
        //
        // > The value of alignment shall be a valid alignment supported by the implementation
        // [...].
        //
        // As an example of the "supported by the implementation" requirement, POSIX.1-2001 (IEEE
        // 1003.1-2001) defines `posix_memalign`:
        //
        // > The value of alignment shall be a power of two multiple of sizeof (void *).
        //
        // and POSIX-based implementations of `aligned_alloc` inherit this requirement. At the time
        // of writing, this is known to be the case on macOS (but not in glibc).
        //
        // Satisfy the stricter requirement to avoid spurious test failures on some platforms.
        let min_align = core::mem::size_of::<*const crate::ffi::c_void>();
        let layout = layout.align_to(min_align).map_err(|_| AllocError)?;
        let layout = layout.pad_to_align();

        // SAFETY: Returns either NULL or a pointer to a memory allocation that satisfies or
        // exceeds the given size and alignment requirements.
        let dst = unsafe { libc_aligned_alloc(layout.align(), layout.size()) }.cast::<u8>();
        let dst = NonNull::new(dst).ok_or(AllocError)?;

        if flags.contains(__GFP_ZERO) {
            // SAFETY: The preceding calls to `libc_aligned_alloc` and `NonNull::new`
            // guarantee that `dst` points to memory of at least `layout.size()` bytes.
            unsafe { dst.as_ptr().write_bytes(0, layout.size()) };
        }

        if !src.is_null() {
            // SAFETY:
            // - `src` has previously been allocated with this `Allocator`; `dst` has just been
            //   newly allocated, hence the memory regions do not overlap.
            // - both` src` and `dst` are properly aligned and valid for reads and writes
            unsafe {
                ptr::copy_nonoverlapping(
                    src,
                    dst.as_ptr(),
                    cmp::min(layout.size(), old_layout.size()),
                )
            };
        }

        // SAFETY: `src` is either NULL or was previously allocated with this `Allocator`
        unsafe { libc_free(src.cast()) };

        Ok(NonNull::slice_from_raw_parts(dst, layout.size()))
    }
}

[ Dauer der Verarbeitung: 0.22 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge