]> git.lizzy.rs Git - rust.git/blob - src/libcore/ffi.rs
Rollup merge of #66503 - thomasetter:panic-error-msg, r=joshtriplett
[rust.git] / src / libcore / ffi.rs
1 #![stable(feature = "", since = "1.30.0")]
2 #![allow(non_camel_case_types)]
3
4 //! Utilities related to FFI bindings.
5
6 use crate::fmt;
7 use crate::marker::PhantomData;
8 use crate::ops::{Deref, DerefMut};
9
10 /// Equivalent to C's `void` type when used as a [pointer].
11 ///
12 /// In essence, `*const c_void` is equivalent to C's `const void*`
13 /// and `*mut c_void` is equivalent to C's `void*`. That said, this is
14 /// *not* the same as C's `void` return type, which is Rust's `()` type.
15 ///
16 /// To model pointers to opaque types in FFI, until `extern type` is
17 /// stabilized, it is recommended to use a newtype wrapper around an empty
18 /// byte array. See the [Nomicon] for details.
19 ///
20 /// One could use `std::os::raw::c_void` if they want to support old Rust
21 /// compiler down to 1.1.0. After Rust 1.30.0, it was re-exported by
22 /// this definition. For more information, please read [RFC 2521].
23 ///
24 /// [pointer]: ../../std/primitive.pointer.html
25 /// [Nomicon]: https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
26 /// [RFC 2521]: https://github.com/rust-lang/rfcs/blob/master/text/2521-c_void-reunification.md
27 // N.B., for LLVM to recognize the void pointer type and by extension
28 //     functions like malloc(), we need to have it represented as i8* in
29 //     LLVM bitcode. The enum used here ensures this and prevents misuse
30 //     of the "raw" type by only having private variants. We need two
31 //     variants, because the compiler complains about the repr attribute
32 //     otherwise and we need at least one variant as otherwise the enum
33 //     would be uninhabited and at least dereferencing such pointers would
34 //     be UB.
35 #[repr(u8)]
36 #[stable(feature = "core_c_void", since = "1.30.0")]
37 pub enum c_void {
38     #[unstable(
39         feature = "c_void_variant",
40         reason = "temporary implementation detail",
41         issue = "0"
42     )]
43     #[doc(hidden)]
44     __variant1,
45     #[unstable(
46         feature = "c_void_variant",
47         reason = "temporary implementation detail",
48         issue = "0"
49     )]
50     #[doc(hidden)]
51     __variant2,
52 }
53
54 #[stable(feature = "std_debug", since = "1.16.0")]
55 impl fmt::Debug for c_void {
56     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57         f.pad("c_void")
58     }
59 }
60
61 /// Basic implementation of a `va_list`.
62 // The name is WIP, using `VaListImpl` for now.
63 #[cfg(any(
64     all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), not(target_arch = "x86_64")),
65     all(target_arch = "aarch64", target_os = "ios"),
66     target_arch = "wasm32",
67     target_arch = "asmjs",
68     windows
69 ))]
70 #[repr(transparent)]
71 #[unstable(
72     feature = "c_variadic",
73     reason = "the `c_variadic` feature has not been properly tested on \
74               all supported platforms",
75     issue = "44930"
76 )]
77 #[lang = "va_list"]
78 pub struct VaListImpl<'f> {
79     ptr: *mut c_void,
80
81     // Invariant over `'f`, so each `VaListImpl<'f>` object is tied to
82     // the region of the function it's defined in
83     _marker: PhantomData<&'f mut &'f c_void>,
84 }
85
86 #[cfg(any(
87     all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), not(target_arch = "x86_64")),
88     all(target_arch = "aarch64", target_os = "ios"),
89     target_arch = "wasm32",
90     target_arch = "asmjs",
91     windows
92 ))]
93 #[unstable(
94     feature = "c_variadic",
95     reason = "the `c_variadic` feature has not been properly tested on \
96               all supported platforms",
97     issue = "44930"
98 )]
99 impl<'f> fmt::Debug for VaListImpl<'f> {
100     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101         write!(f, "va_list* {:p}", self.ptr)
102     }
103 }
104
105 /// AArch64 ABI implementation of a `va_list`. See the
106 /// [AArch64 Procedure Call Standard] for more details.
107 ///
108 /// [AArch64 Procedure Call Standard]:
109 /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
110 #[cfg(all(target_arch = "aarch64", not(target_os = "ios"), not(windows)))]
111 #[repr(C)]
112 #[derive(Debug)]
113 #[unstable(
114     feature = "c_variadic",
115     reason = "the `c_variadic` feature has not been properly tested on \
116               all supported platforms",
117     issue = "44930"
118 )]
119 #[lang = "va_list"]
120 pub struct VaListImpl<'f> {
121     stack: *mut c_void,
122     gr_top: *mut c_void,
123     vr_top: *mut c_void,
124     gr_offs: i32,
125     vr_offs: i32,
126     _marker: PhantomData<&'f mut &'f c_void>,
127 }
128
129 /// PowerPC ABI implementation of a `va_list`.
130 #[cfg(all(target_arch = "powerpc", not(windows)))]
131 #[repr(C)]
132 #[derive(Debug)]
133 #[unstable(
134     feature = "c_variadic",
135     reason = "the `c_variadic` feature has not been properly tested on \
136               all supported platforms",
137     issue = "44930"
138 )]
139 #[lang = "va_list"]
140 pub struct VaListImpl<'f> {
141     gpr: u8,
142     fpr: u8,
143     reserved: u16,
144     overflow_arg_area: *mut c_void,
145     reg_save_area: *mut c_void,
146     _marker: PhantomData<&'f mut &'f c_void>,
147 }
148
149 /// x86_64 ABI implementation of a `va_list`.
150 #[cfg(all(target_arch = "x86_64", not(windows)))]
151 #[repr(C)]
152 #[derive(Debug)]
153 #[unstable(
154     feature = "c_variadic",
155     reason = "the `c_variadic` feature has not been properly tested on \
156               all supported platforms",
157     issue = "44930"
158 )]
159 #[lang = "va_list"]
160 pub struct VaListImpl<'f> {
161     gp_offset: i32,
162     fp_offset: i32,
163     overflow_arg_area: *mut c_void,
164     reg_save_area: *mut c_void,
165     _marker: PhantomData<&'f mut &'f c_void>,
166 }
167
168 /// A wrapper for a `va_list`
169 #[repr(transparent)]
170 #[derive(Debug)]
171 #[unstable(
172     feature = "c_variadic",
173     reason = "the `c_variadic` feature has not been properly tested on \
174               all supported platforms",
175     issue = "44930"
176 )]
177 pub struct VaList<'a, 'f: 'a> {
178     #[cfg(any(
179         all(
180             not(target_arch = "aarch64"),
181             not(target_arch = "powerpc"),
182             not(target_arch = "x86_64")
183         ),
184         all(target_arch = "aarch64", target_os = "ios"),
185         target_arch = "wasm32",
186         target_arch = "asmjs",
187         windows
188     ))]
189     inner: VaListImpl<'f>,
190
191     #[cfg(all(
192         any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"),
193         any(not(target_arch = "aarch64"), not(target_os = "ios")),
194         not(target_arch = "wasm32"),
195         not(target_arch = "asmjs"),
196         not(windows)
197     ))]
198     inner: &'a mut VaListImpl<'f>,
199
200     _marker: PhantomData<&'a mut VaListImpl<'f>>,
201 }
202
203 #[cfg(any(
204     all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), not(target_arch = "x86_64")),
205     all(target_arch = "aarch64", target_os = "ios"),
206     target_arch = "wasm32",
207     target_arch = "asmjs",
208     windows
209 ))]
210 #[unstable(
211     feature = "c_variadic",
212     reason = "the `c_variadic` feature has not been properly tested on \
213               all supported platforms",
214     issue = "44930"
215 )]
216 impl<'f> VaListImpl<'f> {
217     /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`.
218     #[inline]
219     pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> {
220         VaList { inner: VaListImpl { ..*self }, _marker: PhantomData }
221     }
222 }
223
224 #[cfg(all(
225     any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"),
226     any(not(target_arch = "aarch64"), not(target_os = "ios")),
227     not(target_arch = "wasm32"),
228     not(target_arch = "asmjs"),
229     not(windows)
230 ))]
231 #[unstable(
232     feature = "c_variadic",
233     reason = "the `c_variadic` feature has not been properly tested on \
234               all supported platforms",
235     issue = "44930"
236 )]
237 impl<'f> VaListImpl<'f> {
238     /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`.
239     #[inline]
240     pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> {
241         VaList { inner: self, _marker: PhantomData }
242     }
243 }
244
245 #[unstable(
246     feature = "c_variadic",
247     reason = "the `c_variadic` feature has not been properly tested on \
248               all supported platforms",
249     issue = "44930"
250 )]
251 impl<'a, 'f: 'a> Deref for VaList<'a, 'f> {
252     type Target = VaListImpl<'f>;
253
254     #[inline]
255     fn deref(&self) -> &VaListImpl<'f> {
256         &self.inner
257     }
258 }
259
260 #[unstable(
261     feature = "c_variadic",
262     reason = "the `c_variadic` feature has not been properly tested on \
263               all supported platforms",
264     issue = "44930"
265 )]
266 impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> {
267     #[inline]
268     fn deref_mut(&mut self) -> &mut VaListImpl<'f> {
269         &mut self.inner
270     }
271 }
272
273 // The VaArgSafe trait needs to be used in public interfaces, however, the trait
274 // itself must not be allowed to be used outside this module. Allowing users to
275 // implement the trait for a new type (thereby allowing the va_arg intrinsic to
276 // be used on a new type) is likely to cause undefined behavior.
277 //
278 // FIXME(dlrobertson): In order to use the VaArgSafe trait in a public interface
279 // but also ensure it cannot be used elsewhere, the trait needs to be public
280 // within a private module. Once RFC 2145 has been implemented look into
281 // improving this.
282 mod sealed_trait {
283     /// Trait which whitelists the allowed types to be used with [VaList::arg]
284     ///
285     /// [VaList::va_arg]: struct.VaList.html#method.arg
286     #[unstable(
287         feature = "c_variadic",
288         reason = "the `c_variadic` feature has not been properly tested on \
289                   all supported platforms",
290         issue = "44930"
291     )]
292     pub trait VaArgSafe {}
293 }
294
295 macro_rules! impl_va_arg_safe {
296     ($($t:ty),+) => {
297         $(
298             #[unstable(feature = "c_variadic",
299                        reason = "the `c_variadic` feature has not been properly tested on \
300                                  all supported platforms",
301                        issue = "44930")]
302             impl sealed_trait::VaArgSafe for $t {}
303         )+
304     }
305 }
306
307 impl_va_arg_safe! {i8, i16, i32, i64, usize}
308 impl_va_arg_safe! {u8, u16, u32, u64, isize}
309 impl_va_arg_safe! {f64}
310
311 #[unstable(
312     feature = "c_variadic",
313     reason = "the `c_variadic` feature has not been properly tested on \
314               all supported platforms",
315     issue = "44930"
316 )]
317 impl<T> sealed_trait::VaArgSafe for *mut T {}
318 #[unstable(
319     feature = "c_variadic",
320     reason = "the `c_variadic` feature has not been properly tested on \
321               all supported platforms",
322     issue = "44930"
323 )]
324 impl<T> sealed_trait::VaArgSafe for *const T {}
325
326 #[unstable(
327     feature = "c_variadic",
328     reason = "the `c_variadic` feature has not been properly tested on \
329               all supported platforms",
330     issue = "44930"
331 )]
332 impl<'f> VaListImpl<'f> {
333     /// Advance to the next arg.
334     #[inline]
335     pub unsafe fn arg<T: sealed_trait::VaArgSafe>(&mut self) -> T {
336         va_arg(self)
337     }
338
339     /// Copies the `va_list` at the current location.
340     pub unsafe fn with_copy<F, R>(&self, f: F) -> R
341     where
342         F: for<'copy> FnOnce(VaList<'copy, 'f>) -> R,
343     {
344         let mut ap = self.clone();
345         let ret = f(ap.as_va_list());
346         va_end(&mut ap);
347         ret
348     }
349 }
350
351 #[unstable(
352     feature = "c_variadic",
353     reason = "the `c_variadic` feature has not been properly tested on \
354               all supported platforms",
355     issue = "44930"
356 )]
357 impl<'f> Clone for VaListImpl<'f> {
358     #[inline]
359     fn clone(&self) -> Self {
360         let mut dest = crate::mem::MaybeUninit::uninit();
361         // SAFETY: we write to the `MaybeUninit`, thus it is initialized and `assume_init` is legal
362         unsafe {
363             va_copy(dest.as_mut_ptr(), self);
364             dest.assume_init()
365         }
366     }
367 }
368
369 #[unstable(
370     feature = "c_variadic",
371     reason = "the `c_variadic` feature has not been properly tested on \
372               all supported platforms",
373     issue = "44930"
374 )]
375 impl<'f> Drop for VaListImpl<'f> {
376     fn drop(&mut self) {
377         // FIXME: this should call `va_end`, but there's no clean way to
378         // guarantee that `drop` always gets inlined into its caller,
379         // so the `va_end` would get directly called from the same function as
380         // the corresponding `va_copy`. `man va_end` states that C requires this,
381         // and LLVM basically follows the C semantics, so we need to make sure
382         // that `va_end` is always called from the same function as `va_copy`.
383         // For more details, see https://github.com/rust-lang/rust/pull/59625
384         // and https://llvm.org/docs/LangRef.html#llvm-va-end-intrinsic.
385         //
386         // This works for now, since `va_end` is a no-op on all current LLVM targets.
387     }
388 }
389
390 extern "rust-intrinsic" {
391     /// Destroy the arglist `ap` after initialization with `va_start` or
392     /// `va_copy`.
393     fn va_end(ap: &mut VaListImpl<'_>);
394
395     /// Copies the current location of arglist `src` to the arglist `dst`.
396     fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>);
397
398     /// Loads an argument of type `T` from the `va_list` `ap` and increment the
399     /// argument `ap` points to.
400     fn va_arg<T: sealed_trait::VaArgSafe>(ap: &mut VaListImpl<'_>) -> T;
401 }