File: malloc.rs

package info (click to toggle)
rust-coreutils 0.7.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 505,620 kB
  • sloc: ansic: 103,594; asm: 28,570; sh: 8,910; python: 5,581; makefile: 472; cpp: 97; javascript: 72
file content (140 lines) | stat: -rw-r--r-- 4,030 bytes parent folder | download | duplicates (5)
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
//! A minimal alternative to crates like `malloc_buf`, `mbox` and `malloced`.
use core::ffi::c_char;
use core::ffi::CStr;
use core::fmt;
use core::marker::PhantomData;
use core::ops::Deref;
use core::ptr::{self, NonNull};

use crate::ffi;

#[repr(transparent)]
pub(crate) struct MallocSlice<T> {
    ptr: NonNull<[T]>,
    // Necessary for dropck
    _p: PhantomData<[T]>,
}

impl<T> MallocSlice<T> {
    pub(crate) unsafe fn from_array(mut ptr: *mut T, len: usize) -> Self {
        // If the length is 0, the pointer is usually NULL, and as such we
        // need to conjure some other pointer (slices are always non-null).
        if len == 0 {
            ptr = NonNull::dangling().as_ptr();
        }

        let ptr = ptr::slice_from_raw_parts_mut(ptr, len);
        let ptr = NonNull::new(ptr).expect("tried to construct MallocSlice from a NULL pointer");
        Self {
            ptr,
            _p: PhantomData,
        }
    }

    fn len(&self) -> usize {
        // TODO: Use `self.ptr.len()` once in MSRV
        (**self).len()
    }
}

impl<T> Drop for MallocSlice<T> {
    #[allow(clippy::len_zero)]
    fn drop(&mut self) {
        // If the length is 0, then the pointer is dangling from `from_array`
        // (since the length is immutable), and we can skip calling `free`.
        if self.len() != 0 {
            // SAFETY: We take ownership over the slice elements in
            // `from_array`.
            unsafe { ptr::drop_in_place(self.ptr.as_ptr()) };
            // SAFETY: We take ownership over the pointer in `from_array`,
            // and the pointer is valid if the length is non-zero.
            unsafe { ffi::free(self.ptr.cast().as_ptr()) };
        }
    }
}

impl<T> Deref for MallocSlice<T> {
    type Target = [T];

    #[inline]
    fn deref(&self) -> &[T] {
        // SAFETY:
        // - That the pointer is aligned, dereferenceable and initialized is
        //   ensured by the caller of `from_array` (which usually get it from
        //   some external API that will do this for you).
        // - The lifetime is bound to the `MallocSlice`, which in turn ensures
        //   the pointer is valid until it is dropped.
        unsafe { self.ptr.as_ref() }
    }
}

impl<T: fmt::Debug> fmt::Debug for MallocSlice<T> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&**self, f)
    }
}

impl<T> AsRef<[T]> for MallocSlice<T> {
    #[inline]
    fn as_ref(&self) -> &[T] {
        self
    }
}

#[repr(transparent)]
pub(crate) struct MallocCStr {
    ptr: NonNull<CStr>,
}

impl MallocCStr {
    pub(crate) unsafe fn from_c_str(ptr: *mut c_char) -> Self {
        if ptr.is_null() {
            panic!("tried to construct MallocStr from a NULL pointer");
        }
        // SAFETY: We just checked that the pointer is not NULL.
        //
        // Further validity of the pointer is ensured by the caller.
        let cstr = unsafe { CStr::from_ptr(ptr) };
        // Note that we construct this `NonNull` from an immutable reference
        // (there is not yet a `CStr::from_mut_ptr`).
        //
        // This means that we're (probably) no longer allowed to mutate the
        // value, if that is desired for `MallocStr` in the future, then we'll
        // have to implement this method a bit differently.
        let ptr = NonNull::from(cstr);
        Self { ptr }
    }
}

impl Drop for MallocCStr {
    #[inline]
    fn drop(&mut self) {
        // SAFETY: We take ownership in `from_c_str`.
        unsafe { ffi::free(self.ptr.cast().as_ptr()) };
    }
}

impl Deref for MallocCStr {
    type Target = CStr;

    #[inline]
    fn deref(&self) -> &CStr {
        // SAFETY: Same as `MallocSlice::deref`
        unsafe { self.ptr.as_ref() }
    }
}

impl fmt::Debug for MallocCStr {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&**self, f)
    }
}

impl AsRef<CStr> for MallocCStr {
    #[inline]
    fn as_ref(&self) -> &CStr {
        self
    }
}