ffi.rs.html -- source
Description: Source to the Rust file `src/libcore/ffi.rs`.
Keywords: rust, rustlang, rust-lang

      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
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355

    #![stable(feature = "", since = "1.30.0")]

    #![allow(non_camel_case_types)]

    //! Utilities related to FFI bindings.

    use crate::fmt;
    use crate::marker::PhantomData;
    use crate::ops::{Deref, DerefMut};

    /// Equivalent to C's `void` type when used as a [pointer].
    ///
    /// In essence, `*const c_void` is equivalent to C's `const void*`
    /// and `*mut c_void` is equivalent to C's `void*`. That said, this is
    /// *not* the same as C's `void` return type, which is Rust's `()` type.
    ///
    /// To model pointers to opaque types in FFI, until `extern type` is
    /// stabilized, it is recommended to use a newtype wrapper around an empty
    /// byte array. See the [Nomicon] for details.
    ///
    /// One could use `std::os::raw::c_void` if they want to support old Rust
    /// compiler down to 1.1.0. After Rust 1.30.0, it was re-exported by
    /// this definition. For more information, please read [RFC 2521].
    ///
    /// [pointer]: ../../std/primitive.pointer.html
    /// [Nomicon]: https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
    /// [RFC 2521]: https://github.com/rust-lang/rfcs/blob/master/text/2521-c_void-reunification.md
    // N.B., for LLVM to recognize the void pointer type and by extension
    //     functions like malloc(), we need to have it represented as i8* in
    //     LLVM bitcode. The enum used here ensures this and prevents misuse
    //     of the "raw" type by only having private variants. We need two
    //     variants, because the compiler complains about the repr attribute
    //     otherwise and we need at least one variant as otherwise the enum
    //     would be uninhabited and at least dereferencing such pointers would
    //     be UB.
    #[repr(u8)]
    #[stable(feature = "core_c_void", since = "1.30.0")]
    pub enum c_void {
        #[unstable(feature = "c_void_variant", reason = "temporary implementation detail",
                   issue = "0")]
        #[doc(hidden)] __variant1,
        #[unstable(feature = "c_void_variant", reason = "temporary implementation detail",
                   issue = "0")]
        #[doc(hidden)] __variant2,
    }

    #[stable(feature = "std_debug", since = "1.16.0")]
    impl fmt::Debug for c_void {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.pad("c_void")
        }
    }

    /// Basic implementation of a `va_list`.
    // The name is WIP, using `VaListImpl` for now.
    #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
                  not(target_arch = "x86_64")),
              all(target_arch = "aarch64", target_os = "ios"),
              target_arch = "wasm32",
              target_arch = "asmjs",
              windows))]
    #[repr(transparent)]
    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "44930")]
    #[lang = "va_list"]
    pub struct VaListImpl<'f> {
        ptr: *mut c_void,

        // Invariant over `'f`, so each `VaListImpl<'f>` object is tied to
        // the region of the function it's defined in
        _marker: PhantomData<&'f mut &'f c_void>,
    }

    #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
                  not(target_arch = "x86_64")),
              all(target_arch = "aarch64", target_os = "ios"),
              target_arch = "wasm32",
              target_arch = "asmjs",
              windows))]
    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "44930")]
    impl<'f> fmt::Debug for VaListImpl<'f> {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            write!(f, "va_list* {:p}", self.ptr)
        }
    }

    /// AArch64 ABI implementation of a `va_list`. See the
    /// [AArch64 Procedure Call Standard] for more details.
    ///
    /// [AArch64 Procedure Call Standard]:
    /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
    #[cfg(all(target_arch = "aarch64", not(target_os = "ios"), not(windows)))]
    #[repr(C)]
    #[derive(Debug)]
    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "44930")]
    #[lang = "va_list"]
    pub struct VaListImpl<'f> {
        stack: *mut c_void,
        gr_top: *mut c_void,
        vr_top: *mut c_void,
        gr_offs: i32,
        vr_offs: i32,
        _marker: PhantomData<&'f mut &'f c_void>,
    }

    /// PowerPC ABI implementation of a `va_list`.
    #[cfg(all(target_arch = "powerpc", not(windows)))]
    #[repr(C)]
    #[derive(Debug)]
    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "44930")]
    #[lang = "va_list"]
    pub struct VaListImpl<'f> {
        gpr: u8,
        fpr: u8,
        reserved: u16,
        overflow_arg_area: *mut c_void,
        reg_save_area: *mut c_void,
        _marker: PhantomData<&'f mut &'f c_void>,
    }

    /// x86_64 ABI implementation of a `va_list`.
    #[cfg(all(target_arch = "x86_64", not(windows)))]
    #[repr(C)]
    #[derive(Debug)]
    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "44930")]
    #[lang = "va_list"]
    pub struct VaListImpl<'f> {
        gp_offset: i32,
        fp_offset: i32,
        overflow_arg_area: *mut c_void,
        reg_save_area: *mut c_void,
        _marker: PhantomData<&'f mut &'f c_void>,
    }

    /// A wrapper for a `va_list`
    #[repr(transparent)]
    #[derive(Debug)]
    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "44930")]
    pub struct VaList<'a, 'f: 'a> {
        #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
                      not(target_arch = "x86_64")),
                  all(target_arch = "aarch64", target_os = "ios"),
                  target_arch = "wasm32",
                  target_arch = "asmjs",
                  windows))]
        inner: VaListImpl<'f>,

        #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc",
                      target_arch = "x86_64"),
                  any(not(target_arch = "aarch64"), not(target_os = "ios")),
                  not(target_arch = "wasm32"),
                  not(target_arch = "asmjs"),
                  not(windows)))]
        inner: &'a mut VaListImpl<'f>,

        _marker: PhantomData<&'a mut VaListImpl<'f>>,
    }

    #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
                  not(target_arch = "x86_64")),
              all(target_arch = "aarch64", target_os = "ios"),
              target_arch = "wasm32",
              target_arch = "asmjs",
              windows))]
    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "44930")]
    impl<'f> VaListImpl<'f> {
        /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`.
        #[inline]
        pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> {
            VaList {
                inner: VaListImpl { ..*self },
                _marker: PhantomData,
            }
        }
    }

    #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc",
                  target_arch = "x86_64"),
              any(not(target_arch = "aarch64"), not(target_os = "ios")),
              not(target_arch = "wasm32"),
              not(target_arch = "asmjs"),
              not(windows)))]
    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "44930")]
    impl<'f> VaListImpl<'f> {
        /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`.
        #[inline]
        pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> {
            VaList {
                inner: self,
                _marker: PhantomData,
            }
        }
    }

    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "44930")]
    impl<'a, 'f: 'a> Deref for VaList<'a, 'f> {
        type Target = VaListImpl<'f>;

        #[inline]
        fn deref(&self) -> &VaListImpl<'f> {
            &self.inner
        }
    }

    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "44930")]
    impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> {
        #[inline]
        fn deref_mut(&mut self) -> &mut VaListImpl<'f> {
            &mut self.inner
        }
    }

    // The VaArgSafe trait needs to be used in public interfaces, however, the trait
    // itself must not be allowed to be used outside this module. Allowing users to
    // implement the trait for a new type (thereby allowing the va_arg intrinsic to
    // be used on a new type) is likely to cause undefined behavior.
    //
    // FIXME(dlrobertson): In order to use the VaArgSafe trait in a public interface
    // but also ensure it cannot be used elsewhere, the trait needs to be public
    // within a private module. Once RFC 2145 has been implemented look into
    // improving this.
    mod sealed_trait {
        /// Trait which whitelists the allowed types to be used with [VaList::arg]
        ///
        /// [VaList::va_arg]: struct.VaList.html#method.arg
        #[unstable(feature = "c_variadic",
                   reason = "the `c_variadic` feature has not been properly tested on \
                             all supported platforms",
                   issue = "44930")]
        pub trait VaArgSafe {}
    }

    macro_rules! impl_va_arg_safe {
        ($($t:ty),+) => {
            $(
                #[unstable(feature = "c_variadic",
                           reason = "the `c_variadic` feature has not been properly tested on \
                                     all supported platforms",
                           issue = "44930")]
                impl sealed_trait::VaArgSafe for $t {}
            )+
        }
    }

    impl_va_arg_safe!{i8, i16, i32, i64, usize}
    impl_va_arg_safe!{u8, u16, u32, u64, isize}
    impl_va_arg_safe!{f64}

    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "44930")]
    impl<T> sealed_trait::VaArgSafe for *mut T {}
    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "44930")]
    impl<T> sealed_trait::VaArgSafe for *const T {}

    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "44930")]
    impl<'f> VaListImpl<'f> {
        /// Advance to the next arg.
        #[inline]
        pub unsafe fn arg<T: sealed_trait::VaArgSafe>(&mut self) -> T {
            va_arg(self)
        }

        /// Copies the `va_list` at the current location.
        pub unsafe fn with_copy<F, R>(&self, f: F) -> R
                where F: for<'copy> FnOnce(VaList<'copy, 'f>) -> R {
            let mut ap = self.clone();
            let ret = f(ap.as_va_list());
            va_end(&mut ap);
            ret
        }
    }

    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "44930")]
    impl<'f> Clone for VaListImpl<'f> {
        #[inline]
        fn clone(&self) -> Self {
            let mut dest = crate::mem::MaybeUninit::uninit();
            unsafe {
                va_copy(dest.as_mut_ptr(), self);
                dest.assume_init()
            }
        }
    }

    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "44930")]
    impl<'f> Drop for VaListImpl<'f> {
        fn drop(&mut self) {
            // FIXME: this should call `va_end`, but there's no clean way to
            // guarantee that `drop` always gets inlined into its caller,
            // so the `va_end` would get directly called from the same function as
            // the corresponding `va_copy`. `man va_end` states that C requires this,
            // and LLVM basically follows the C semantics, so we need to make sure
            // that `va_end` is always called from the same function as `va_copy`.
            // For more details, see https://github.com/rust-lang/rust/pull/59625
            // and https://llvm.org/docs/LangRef.html#llvm-va-end-intrinsic.
            //
            // This works for now, since `va_end` is a no-op on all current LLVM targets.
        }
    }

    extern "rust-intrinsic" {
        /// Destroy the arglist `ap` after initialization with `va_start` or
        /// `va_copy`.
        fn va_end(ap: &mut VaListImpl<'_>);

        /// Copies the current location of arglist `src` to the arglist `dst`.
        fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>);

        /// Loads an argument of type `T` from the `va_list` `ap` and increment the
        /// argument `ap` points to.
        fn va_arg<T: sealed_trait::VaArgSafe>(ap: &mut VaListImpl<'_>) -> T;
    }