Skip to main content

rustc_sanitizers/ignorelist/
ffi.rs

1use std::cell::RefCell;
2use std::ffi::c_char;
3use std::ptr;
4use std::string::FromUtf8Error;
5
6use libc::size_t;
7
8#[repr(C)]
9#[derive(#[automatically_derived]
impl ::core::marker::Copy for Blame { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for Blame { }
#[automatically_derived]
impl ::core::clone::Clone for Blame {
    #[inline]
    fn clone(&self) -> Blame {
        let _: ::core::clone::AssertParamIsClone<u32>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for Blame {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "Blame",
            "file_idx", &self.file_idx, "line_no", &&self.line_no)
    }
}Debug, #[automatically_derived]
impl ::core::default::Default for Blame {
    #[inline]
    fn default() -> Blame {
        Blame {
            file_idx: ::core::default::Default::default(),
            line_no: ::core::default::Default::default(),
        }
    }
}Default, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for Blame { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Blame {
    #[inline]
    fn eq(&self, other: &Blame) -> bool {
        self.file_idx == other.file_idx && self.line_no == other.line_no
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for Blame {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<u32>;
    }
}Eq, #[automatically_derived]
impl ::core::cmp::PartialOrd for Blame {
    #[inline]
    fn partial_cmp(&self, other: &Blame)
        -> ::core::option::Option<::core::cmp::Ordering> {
        ::core::option::Option::Some(::core::cmp::Ord::cmp(self, other))
    }
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for Blame {
    #[inline]
    fn cmp(&self, other: &Blame) -> ::core::cmp::Ordering {
        match ::core::cmp::Ord::cmp(&self.file_idx, &other.file_idx) {
            ::core::cmp::Ordering::Equal =>
                ::core::cmp::Ord::cmp(&self.line_no, &other.line_no),
            cmp => cmp,
        }
    }
}Ord)]
10pub struct Blame {
11    pub file_idx: u32,
12    pub line_no: u32,
13}
14
15impl Blame {
16    pub const NONE: Self = Self { file_idx: 0, line_no: 0 };
17
18    #[inline]
19    pub fn is_none(self) -> bool {
20        self.line_no == 0
21    }
22
23    #[inline]
24    pub fn is_some(self) -> bool {
25        self.line_no != 0
26    }
27}
28
29unsafe extern "C" {
30    pub(crate) type Opaque;
31    /// Opaque type that allows C++ code to write bytes to a Rust-side buffer,
32    /// in conjunction with `RawRustStringOstream`. Use this as `&RustString`
33    /// (Rust) and `RustStringRef` (C++) in FFI signatures.
34    pub(crate) type RustString;
35
36    pub(crate) fn LLVMRustSpecialCaseListCreate(
37        Paths: *const *const c_char,
38        NumPaths: size_t,
39        ErrorMsg: &RustString,
40    ) -> *mut Opaque;
41
42    pub(crate) fn LLVMRustSpecialCaseListDestroy(List: *mut Opaque);
43    pub(crate) fn LLVMRustSpecialCaseListInSectionBlame(
44        List: *const Opaque,
45        Mask: u32,
46        Section: *const c_char,
47        Prefix: *const c_char,
48        Query: *const c_char,
49        OutNoSan: *mut Blame,
50        OutSan: *mut Blame,
51    );
52}
53
54/// Underlying implementation of [`RustString`].
55///
56/// Having two separate types makes it possible to use the opaque [`RustString`]
57/// in FFI signatures without `improper_ctypes` warnings. This is a workaround
58/// for the fact that there is no way to opt out of `improper_ctypes` when
59/// _declaring_ a type (as opposed to using that type).
60#[derive(#[automatically_derived]
impl ::core::default::Default for RustStringInner {
    #[inline]
    fn default() -> RustStringInner {
        RustStringInner { bytes: ::core::default::Default::default() }
    }
}Default)]
61struct RustStringInner {
62    bytes: RefCell<Vec<u8>>,
63}
64
65impl RustStringInner {
66    fn as_opaque(&self) -> &RustString {
67        let ptr: *const RustStringInner = ptr::from_ref(self);
68        // We can't use `ptr::cast` here because extern types are `!Sized`.
69        let ptr = ptr as *const RustString;
70        unsafe {
71            // Safety: `self` outlives returned `&RustString` and it is originated from `rustc`
72            &*ptr
73        }
74    }
75
76    fn into_inner(self) -> Vec<u8> {
77        self.bytes.into_inner()
78    }
79}
80
81impl RustString {
82    pub(crate) fn build_byte_buffer(closure: impl FnOnce(&Self)) -> Vec<u8> {
83        let buf = RustStringInner::default();
84        closure(buf.as_opaque());
85        buf.into_inner()
86    }
87}
88
89pub(crate) fn build_string(f: impl FnOnce(&RustString)) -> Result<String, FromUtf8Error> {
90    String::from_utf8(RustString::build_byte_buffer(f))
91}