summaryrefslogtreecommitdiff
path: root/src/panic.rs
blob: 4b8489c94732cd3cd9569a686653a07511a8c5e0 (plain)
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
use libc::EINVAL;

use crate::enums::rustls_tls_version;
use crate::error::{rustls_io_result, rustls_result};
use crate::rslice::{rustls_slice_bytes, rustls_str};

use std::ptr::{null, null_mut};

// We wrap all function calls in an ffi_panic_boundary! macro, which catches
// panics and early-returns from the function. For functions that return
// rustls_result, we return a dedicated error code: `Panic`. For functions
// that don't return rustls_result, we return a default value: false, 0, or
// null. This trait provides that logic.
pub(crate) trait PanicOrDefault {
    fn value() -> Self;
}

// This trait is like PanicOrDefault, but returns rustls_result::NullParameter
// rather than `Panic`.
pub(crate) trait NullParameterOrDefault {
    fn value() -> Self;
}

// Defaultable is a subset of Default that can be returned by rustls-ffi.
// We use this rather than Default directly so that we can do a blanket
// impl for `T: Defaultable`. The compiler disallows a blanket impl for
// `T: Default` because `std::default` could later implement `Default`
// for `*mut T` and `*const T`.
pub(crate) trait Defaultable: Default {}

impl Defaultable for u16 {}

impl Defaultable for usize {}

impl Defaultable for bool {}

impl Defaultable for () {}

impl Defaultable for rustls_tls_version {}

impl<T> Defaultable for Option<T> {}

impl<'a> Defaultable for rustls_slice_bytes<'a> {}

impl<T: Defaultable> PanicOrDefault for T {
    fn value() -> Self {
        Default::default()
    }
}

impl<T> PanicOrDefault for *mut T {
    fn value() -> Self {
        null_mut()
    }
}

impl<T> PanicOrDefault for *const T {
    fn value() -> Self {
        null()
    }
}

impl PanicOrDefault for rustls_result {
    fn value() -> Self {
        rustls_result::Panic
    }
}

impl<'a> PanicOrDefault for rustls_str<'a> {
    fn value() -> Self {
        rustls_str::from_str_unchecked("")
    }
}

impl PanicOrDefault for rustls_io_result {
    fn value() -> Self {
        rustls_io_result(EINVAL)
    }
}

impl<T: Defaultable> NullParameterOrDefault for T {
    fn value() -> Self {
        Default::default()
    }
}

impl<T> NullParameterOrDefault for *mut T {
    fn value() -> Self {
        null_mut()
    }
}

impl<T> NullParameterOrDefault for *const T {
    fn value() -> Self {
        null()
    }
}

impl NullParameterOrDefault for rustls_result {
    fn value() -> Self {
        rustls_result::NullParameter
    }
}

impl NullParameterOrDefault for rustls_io_result {
    fn value() -> Self {
        rustls_io_result(EINVAL)
    }
}

impl<'a> NullParameterOrDefault for rustls_str<'a> {
    fn value() -> Self {
        rustls_str::from_str_unchecked("")
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! ffi_panic_boundary {
    ( $($tt:tt)* ) => {
        match ::std::panic::catch_unwind(|| {
            $($tt)*
        }) {
            Ok(ret) => ret,
            Err(_) => return $crate::PanicOrDefault::value(),
        }
    }
}