• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

facet-rs / facet / 15172242552

21 May 2025 08:46PM UTC coverage: 57.185% (-0.4%) from 57.566%
15172242552

Pull #657

github

web-flow
Merge 84199c053 into ddae0c1a3
Pull Request #657: Fix UB for unsized types

33 of 171 new or added lines in 6 files covered. (19.3%)

4 existing lines in 1 file now uncovered.

9475 of 16569 relevant lines covered (57.19%)

135.69 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

57.47
/facet-core/src/impls_core/pointer.rs
1
use core::{fmt, hash::Hash, mem::transmute};
2

3
use crate::{
4
    CmpFn, CmpFnTyped, DebugFn, DebugFnTyped, DisplayFn, DisplayFnTyped, Facet, HashFn,
5
    HashFnTyped, HasherProxy, MarkerTraits, PartialEqFn, PartialEqFnTyped, PartialOrdFn,
6
    PartialOrdFnTyped, PointerType, Shape, Type, TypeParam, ValuePointerType, ValueVTable,
7
};
8

9
macro_rules! impl_facet_for_pointer {
10
    ($variant:ident: $type:ty => $shape:expr => $vtable_builder:expr => $ptr_type:ident, $mutable:expr) => {
11
        unsafe impl<'a, T: Facet<'a> + ?Sized> Facet<'a> for $type {
12
            const VTABLE: &'static ValueVTable = &const {
13
                $vtable_builder
14
                    .type_name(|f, opts| {
34✔
15
                        if let Some(opts) = opts.for_children() {
34✔
16
                            if stringify!($ptr_type) == "Raw" {
34✔
17
                                if $mutable {
18
                                    write!(f, "*mut ")?;
2✔
19
                                } else {
20
                                    write!(f, "*const ")?;
6✔
21
                                }
22
                            } else {
23
                                write!(f, "&")?;
26✔
24
                                if $mutable {
25
                                    write!(f, "mut ")?;
4✔
26
                                }
22✔
27
                            }
28
                            (T::VTABLE.type_name)(f, opts)
34✔
29
                        } else {
30
                            if stringify!($ptr_type) == "Raw" {
×
31
                                if $mutable {
32
                                    write!(f, "*mut ⋯")
×
33
                                } else {
34
                                    write!(f, "*const ⋯")
×
35
                                }
36
                            } else {
37
                                write!(f, "&")?;
×
38
                                if $mutable {
39
                                    write!(f, "mut ⋯")
×
40
                                } else {
41
                                    write!(f, "⋯")
×
42
                                }
43
                            }
44
                        }
45
                    })
34✔
46
                    .build()
47
            };
48

49
            const SHAPE: &'static Shape<'static> = &const {
50
                $shape
51
                    .type_params(&[TypeParam {
52
                        name: "T",
53
                        shape: || T::SHAPE,
54
                    }])
55
                    .ty({
56
                        let is_wide =
57
                            ::core::mem::size_of::<$type>() != ::core::mem::size_of::<*const ()>();
58
                        let vpt = ValuePointerType {
59
                            mutable: $mutable,
60
                            wide: is_wide,
61
                            target: || T::SHAPE,
62
                        };
63

64
                        Type::Pointer(PointerType::$ptr_type(vpt))
65
                    })
66
                    .build()
67
            };
68
        }
69
    };
70
}
71

72
// *const pointers
73
impl_facet_for_pointer!(
74
    Raw: *const T
75
        => Shape::builder_for_sized::<Self>()
76
            .inner(|| T::SHAPE)
77
        => ValueVTable::builder::<Self>()
78
            .marker_traits(
79
                MarkerTraits::EQ
80
                    .union(MarkerTraits::COPY)
81
                    .union(MarkerTraits::UNPIN),
82
            )
83
            .debug(fmt::Debug::fmt)
84
            .clone_into(|src, dst| unsafe { dst.put(*src) })
×
85
            .eq(|left, right| left.cast::<()>().eq(&right.cast::<()>()))
3✔
86
            .partial_ord(|&left, &right| {
3✔
87
                left.cast::<()>().partial_cmp(&right.cast::<()>())
3✔
88
            })
3✔
89
            .ord(|&left, &right| left.cast::<()>().cmp(&right.cast::<()>()))
×
90
            .hash(|value, hasher_this, hasher_write_fn| {
×
91
                value.hash(&mut unsafe {
×
92
                    HasherProxy::new(hasher_this, hasher_write_fn)
×
93
                })
×
94
            })
×
95
        => Raw, false
96
);
97

98
// *mut pointers
99
impl_facet_for_pointer!(
100
    Raw: *mut T
101
        => Shape::builder_for_sized::<Self>()
102
            .inner(|| T::SHAPE)
103
        => ValueVTable::builder::<Self>()
104
            .marker_traits(
105
                MarkerTraits::EQ
106
                    .union(MarkerTraits::COPY)
107
                    .union(MarkerTraits::UNPIN),
108
            )
109
            .debug(fmt::Debug::fmt)
110
            .clone_into(|src, dst| unsafe { dst.put(*src) })
×
111
            .eq(|left, right| left.cast::<()>().eq(&right.cast::<()>()))
1✔
112
            .partial_ord(|&left, &right| {
1✔
113
                left.cast::<()>().partial_cmp(&right.cast::<()>())
1✔
114
            })
1✔
115
            .ord(|&left, &right| left.cast::<()>().cmp(&right.cast::<()>()))
×
116
            .hash(|value, hasher_this, hasher_write_fn| {
×
117
                value.hash(&mut unsafe {
×
118
                    HasherProxy::new(hasher_this, hasher_write_fn)
×
119
                })
×
120
            })
×
121
        => Raw, true
122
);
123

124
// &T references
125
impl_facet_for_pointer!(
126
    Reference: &'a T
127
        => Shape::builder_for_sized::<Self>()
128
        => {
129
            let mut marker_traits = MarkerTraits::COPY.union(MarkerTraits::UNPIN);
130
            if T::SHAPE.vtable.marker_traits.contains(MarkerTraits::EQ) {
131
                marker_traits = marker_traits.union(MarkerTraits::EQ);
132
            }
133
            if T::SHAPE.vtable.marker_traits.contains(MarkerTraits::SYNC) {
134
                marker_traits = marker_traits.union(MarkerTraits::SEND).union(MarkerTraits::SYNC);
135
            }
136

137
            let mut builder = ValueVTable::builder::<Self>()
138
                .marker_traits(marker_traits)
139
                .clone_into(|src, dst| unsafe { dst.put(core::ptr::read(src)) });
×
140

141
            // Forward trait methods to the underlying type if it implements them
142
            if T::VTABLE.debug.is_some() {
143
                builder = builder.debug(|value, f| {
48✔
144
                    let debug_fn = unsafe { transmute::<DebugFn, DebugFnTyped<T>>(T::VTABLE.debug.unwrap()) };
48✔
145
                    debug_fn(*value, f)
48✔
146
                });
48✔
147
            }
148

149
            if T::VTABLE.display.is_some() {
150
                builder = builder.display(|value, f| {
20✔
151
                    let display_fn = unsafe { transmute::<DisplayFn, DisplayFnTyped<T>>(T::VTABLE.display.unwrap()) };
20✔
152
                    display_fn(*value, f)
20✔
153
                });
20✔
154
            }
155

156
            if T::VTABLE.eq.is_some() {
157
                builder = builder.eq(|a, b| {
7✔
158
                    let eq_fn = unsafe { transmute::<PartialEqFn, PartialEqFnTyped<T>>(T::VTABLE.eq.unwrap()) };
7✔
159
                    eq_fn(*a, *b)
7✔
160
                });
7✔
161
            }
162

163
            if T::VTABLE.partial_ord.is_some() {
164
                builder = builder.partial_ord(|a, b| {
7✔
165
                    let partial_ord_fn = unsafe { transmute::<PartialOrdFn, PartialOrdFnTyped<T>>(T::VTABLE.partial_ord.unwrap()) };
7✔
166
                    partial_ord_fn(*a, *b)
7✔
167
                });
7✔
168
            }
169

170
            if T::VTABLE.ord.is_some() {
171
                builder = builder.ord(|a, b| {
×
NEW
172
                    let ord_fn = unsafe { transmute::<CmpFn, CmpFnTyped<T>>(T::VTABLE.ord.unwrap()) };
×
NEW
173
                    ord_fn(*a, *b)
×
UNCOV
174
                });
×
175
            }
176

177
            if T::VTABLE.hash.is_some() {
178
                builder = builder.hash(|value, hasher_this, hasher_write_fn| {
×
NEW
179
                    let hash_fn = unsafe { transmute::<HashFn, HashFnTyped<T>>(T::VTABLE.hash.unwrap()) };
×
NEW
180
                    hash_fn(*value, hasher_this, hasher_write_fn)
×
UNCOV
181
                });
×
182
            }
183

184
            builder
185
        }
186
        => Reference, false
187
);
188

189
// &mut T references
190
impl_facet_for_pointer!(
191
    Reference: &'a mut T
192
        => Shape::builder_for_sized::<Self>()
193
        => {
194
            let mut marker_traits = MarkerTraits::UNPIN;
195
            if T::SHAPE.vtable.marker_traits.contains(MarkerTraits::EQ) {
196
                marker_traits = marker_traits.union(MarkerTraits::EQ);
197
            }
198
            if T::SHAPE.vtable.marker_traits.contains(MarkerTraits::SEND) {
199
                marker_traits = marker_traits.union(MarkerTraits::SEND);
200
            }
201
            if T::SHAPE.vtable.marker_traits.contains(MarkerTraits::SYNC) {
202
                marker_traits = marker_traits.union(MarkerTraits::SYNC);
203
            }
204

205
            let mut builder = ValueVTable::builder::<Self>()
206
                .marker_traits(marker_traits);
207

208
            // Forward trait methods to the underlying type if it implements them
209
            if T::VTABLE.debug.is_some() {
210
                builder = builder.debug(|value, f| {
12✔
211
                    let debug_fn = unsafe { transmute::<DebugFn, DebugFnTyped<T>>(T::VTABLE.debug.unwrap()) };
12✔
212
                    debug_fn(*value, f)
12✔
213
                });
12✔
214
            }
215

216
            if T::VTABLE.display.is_some() {
217
                builder = builder.display(|value, f| {
6✔
218
                    let display_fn = unsafe { transmute::<DisplayFn, DisplayFnTyped<T>>(T::VTABLE.display.unwrap()) };
6✔
219
                    display_fn(*value, f)
6✔
220
                });
6✔
221
            }
222

223
            if T::VTABLE.eq.is_some() {
224
                builder = builder.eq(|a, b| {
2✔
225
                    let eq_fn = unsafe { transmute::<PartialEqFn, PartialEqFnTyped<T>>(T::VTABLE.eq.unwrap()) };
2✔
226
                    eq_fn(*a, *b)
2✔
227
                });
2✔
228
            }
229

230
            if T::VTABLE.partial_ord.is_some() {
231
                builder = builder.partial_ord(|a, b| {
2✔
232
                    let partial_ord_fn = unsafe { transmute::<PartialOrdFn, PartialOrdFnTyped<T>>(T::VTABLE.partial_ord.unwrap()) };
2✔
233
                    partial_ord_fn(*a, *b)
2✔
234
                });
2✔
235
            }
236

237
            if T::VTABLE.ord.is_some() {
238
                builder = builder.ord(|a, b| {
×
NEW
239
                    let ord_fn = unsafe { transmute::<CmpFn, CmpFnTyped<T>>(T::VTABLE.ord.unwrap()) };
×
NEW
240
                    ord_fn(*a, *b)
×
UNCOV
241
                });
×
242
            }
243

244
            if T::VTABLE.hash.is_some() {
245
                builder = builder.hash(|value, hasher_this, hasher_write_fn| {
×
NEW
246
                    let hash_fn = unsafe { transmute::<HashFn, HashFnTyped<T>>(T::VTABLE.hash.unwrap()) };
×
NEW
247
                    hash_fn(*value, hasher_this, hasher_write_fn)
×
UNCOV
248
                });
×
249
            }
250

251
            builder
252
        }
253
        => Reference, true
254
);
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc