@@ -13,9 +13,8 @@ use crate::util::increase_to_alignment;
13
13
use crate :: { TagTrait , TagType , TagTypeId } ;
14
14
use core:: fmt:: { Debug , Formatter } ;
15
15
use core:: mem;
16
- use core:: ops:: Deref ;
17
16
use core:: ptr;
18
- use multiboot2_common:: ALIGNMENT ;
17
+ use multiboot2_common:: { BytesRef , DynSizedStructure , Header } ;
19
18
20
19
/// The common header that all tags have in common. This type is ABI compatible.
21
20
///
@@ -43,107 +42,48 @@ impl TagHeader {
43
42
}
44
43
}
45
44
46
- /// Wraps a byte slice representing a tag, but guarantees that the memory
47
- /// requirements are fulfilled.
48
- ///
49
- /// This is the only type that can be used to construct a [`GenericTag`].
50
- ///
51
- /// The main reason for this dedicated type is to create fine-grained unit-tests
52
- /// for Miri.
53
- ///
54
- /// # Memory Requirements (for Multiboot and Rust/Miri)
55
- /// - At least as big as a `size_of<TagHeader>()`
56
- /// - at least [`ALIGNMENT`]-aligned
57
- /// - Length is multiple of [`ALIGNMENT`]. In other words, there are enough
58
- /// padding bytes until so that pointer coming right after the last byte
59
- /// is [`ALIGNMENT`]-aligned
60
- #[ derive( Clone , Debug , PartialEq , Eq ) ]
61
- #[ repr( transparent) ]
62
- pub struct TagBytesRef < ' a > ( & ' a [ u8 ] ) ;
63
-
64
- impl < ' a > TryFrom < & ' a [ u8 ] > for TagBytesRef < ' a > {
65
- type Error = MemoryError ;
66
-
67
- fn try_from ( value : & ' a [ u8 ] ) -> Result < Self , Self :: Error > {
68
- if value. len ( ) < mem:: size_of :: < TagHeader > ( ) {
69
- return Err ( MemoryError :: MinLengthNotSatisfied ) ;
70
- }
71
- // Doesn't work as expected: if align_of_val(&value[0]) < ALIGNMENT {
72
- if value. as_ptr ( ) . align_offset ( ALIGNMENT ) != 0 {
73
- return Err ( MemoryError :: WrongAlignment ) ;
74
- }
75
- let padding_bytes = value. len ( ) % ALIGNMENT ;
76
- if padding_bytes != 0 {
77
- return Err ( MemoryError :: MissingPadding ) ;
78
- }
79
- Ok ( Self ( value) )
45
+ impl Header for TagHeader {
46
+ fn payload_len ( & self ) -> usize {
47
+ self . size as usize - size_of :: < Self > ( )
80
48
}
81
49
}
82
50
83
- impl < ' a > Deref for TagBytesRef < ' a > {
84
- type Target = & ' a [ u8 ] ;
85
-
86
- fn deref ( & self ) -> & Self :: Target {
87
- & self . 0
88
- }
89
- }
90
-
91
- /// Errors that occur when constructing a [`TagBytesRef`].
92
- #[ derive( Copy , Clone , Debug , Ord , PartialOrd , Eq , PartialEq , Hash ) ]
93
- pub enum MemoryError {
94
- /// The memory must be at least [`ALIGNMENT`]-aligned.
95
- WrongAlignment ,
96
- /// The memory must cover at least the length of a [`TagHeader`].
97
- MinLengthNotSatisfied ,
98
- /// The buffer misses the terminating padding to the next alignment
99
- /// boundary.
100
- // This is mainly relevant to satisfy Miri. As the spec also mandates an
101
- // alignment, we can rely on this property.
102
- MissingPadding ,
103
- }
104
-
105
51
/// A generic tag serving as base to cast to specific tags. This is a DST
106
52
/// version of [`TagHeader`] that solves various type and memory safety
107
53
/// problems by having a type that owns the whole memory of a tag.
108
- #[ derive( Eq , Ord , PartialEq , PartialOrd , ptr_meta:: Pointee ) ]
109
- #[ repr( C ) ]
110
- pub struct GenericTag {
111
- header : TagHeader ,
112
- /// Payload of the tag that is reflected in the `size` attribute, thus, no
113
- /// padding bytes!
114
- payload : [ u8 ] ,
115
- }
54
+ #[ derive( PartialEq , Eq , ptr_meta:: Pointee ) ]
55
+ #[ repr( transparent) ]
56
+ pub struct GenericTag ( DynSizedStructure < TagHeader > ) ;
116
57
117
58
impl GenericTag {
118
- /// Base size of the DST struct without the dynamic part.
119
- const BASE_SIZE : usize = mem:: size_of :: < TagHeader > ( ) ;
120
-
121
- /// Creates a reference to a [`GenericTag`] from the provided `bytes`
122
- /// [`TagBytesRef`].
123
- pub ( crate ) fn ref_from ( bytes : TagBytesRef ) -> & Self {
124
- let header = bytes. as_ptr ( ) . cast :: < TagHeader > ( ) ;
125
- let header = unsafe { & * header } ;
126
- let dst_len = Self :: dst_len ( header) ;
127
- assert_eq ! ( header. size as usize , Self :: BASE_SIZE + dst_len) ;
128
-
129
- let generic_tag: * const Self = ptr_meta:: from_raw_parts ( bytes. as_ptr ( ) . cast ( ) , dst_len) ;
130
- unsafe { & * generic_tag }
59
+ /// Returns a reference to [`GenericTag`] to interpret the provided memory
60
+ /// as [`GenericTag`].
61
+ ///
62
+ /// # Panics
63
+ // pub fn ref_from<'a>(bytes: &'a [u8]) -> Result<&'a Self, MemoryError> {
64
+ // TODO return result
65
+ pub fn ref_from < ' a > ( bytes : & ' a [ u8 ] ) -> & ' a Self {
66
+ let bytes = BytesRef :: < TagHeader > :: try_from ( bytes) . unwrap ( ) ;
67
+ let inner = DynSizedStructure :: ref_from ( bytes) . unwrap ( ) ;
68
+ let tag = unsafe { mem:: transmute :: < _ , & ' a Self > ( inner) } ;
69
+ tag
131
70
}
132
71
72
+ /// Returns the underlying [`TagHeader`].
133
73
pub const fn header ( & self ) -> & TagHeader {
134
- & self . header
74
+ self . 0 . header ( )
135
75
}
136
76
137
77
#[ cfg( all( test, feature = "builder" ) ) ]
138
78
pub const fn payload ( & self ) -> & [ u8 ] {
139
- & self . payload
79
+ self . 0 . payload ( )
140
80
}
141
81
142
82
/// Casts the generic tag to a specific [`TagTrait`] implementation which
143
83
/// may be a ZST or DST typed tag.
144
84
pub fn cast < T : TagTrait + ?Sized > ( & self ) -> & T {
145
85
let base_ptr = ptr:: addr_of!( * self ) ;
146
- let t_dst_size = T :: dst_len ( & self . header ) ;
86
+ let t_dst_size = T :: dst_len ( & self . 0 . header ( ) ) ;
147
87
let t_ptr = ptr_meta:: from_raw_parts ( base_ptr. cast ( ) , t_dst_size) ;
148
88
let t_ref = unsafe { & * t_ptr } ;
149
89
assert_eq ! ( mem:: size_of_val( self ) , mem:: size_of_val( t_ref) ) ;
@@ -154,7 +94,7 @@ impl GenericTag {
154
94
impl Debug for GenericTag {
155
95
fn fmt ( & self , f : & mut Formatter < ' _ > ) -> core:: fmt:: Result {
156
96
f. debug_struct ( "GenericTag" )
157
- . field ( "header" , & self . header )
97
+ . field ( "header" , & self . 0 . header ( ) )
158
98
. field ( "payload" , & "<bytes>" )
159
99
. finish ( )
160
100
}
@@ -164,8 +104,8 @@ impl TagTrait for GenericTag {
164
104
const ID : TagType = TagType :: Custom ( 0xffffffff ) ;
165
105
166
106
fn dst_len ( header : & TagHeader ) -> usize {
167
- assert ! ( header. size as usize >= Self :: BASE_SIZE ) ;
168
- header. size as usize - Self :: BASE_SIZE
107
+ assert ! ( header. size as usize >= size_of :: < TagHeader > ( ) ) ;
108
+ header. size as usize - size_of :: < TagHeader > ( )
169
109
}
170
110
}
171
111
@@ -227,16 +167,14 @@ impl<'a> Iterator for TagIter<'a> {
227
167
& self . buffer [ from..to]
228
168
} ;
229
169
230
- // Should never fail at this point.
231
- let tag_bytes = TagBytesRef :: try_from ( bytes) . unwrap ( ) ;
232
-
233
- Some ( GenericTag :: ref_from ( tag_bytes) )
170
+ Some ( GenericTag :: ref_from ( bytes) )
234
171
}
235
172
}
236
173
237
174
#[ cfg( test) ]
238
175
mod tests {
239
176
use super :: * ;
177
+ use crate :: TagType ;
240
178
use core:: borrow:: Borrow ;
241
179
use core:: mem;
242
180
use multiboot2_common:: test_utils:: AlignedBytes ;
@@ -251,11 +189,10 @@ mod tests {
251
189
0x13 , 0x37 , 0x13 , 0x37 ,
252
190
] ) ;
253
191
254
- let bytes = TagBytesRef :: try_from ( bytes. borrow ( ) ) . unwrap ( ) ;
255
- let tag = GenericTag :: ref_from ( bytes) ;
256
- assert_eq ! ( tag. header. typ, 0xffff_ffff ) ;
257
- assert_eq ! ( tag. header. size, 16 ) ;
258
- assert_eq ! ( tag. payload. len( ) , 8 ) ;
192
+ let tag = GenericTag :: ref_from ( bytes. borrow ( ) ) ;
193
+ assert_eq ! ( tag. header( ) . typ, 0xffff_ffff ) ;
194
+ assert_eq ! ( tag. header( ) . size, 16 ) ;
195
+ assert_eq ! ( tag. payload( ) . len( ) , 8 ) ;
259
196
}
260
197
261
198
#[ test]
@@ -280,8 +217,7 @@ mod tests {
280
217
0xef , 0xbe , 0xad , 0xde , /* field b: 0x1337_1337 */
281
218
0x37 , 0x13 , 0x37 , 0x13 ,
282
219
] ) ;
283
- let bytes = TagBytesRef :: try_from ( bytes. borrow ( ) ) . unwrap ( ) ;
284
- let tag = GenericTag :: ref_from ( bytes) ;
220
+ let tag = GenericTag :: ref_from ( bytes. borrow ( ) ) ;
285
221
let custom_tag = tag. cast :: < CustomTag > ( ) ;
286
222
287
223
assert_eq ! ( mem:: size_of_val( custom_tag) , 16 ) ;
@@ -316,8 +252,7 @@ mod tests {
316
252
0x37 , 0x13 , 0x37 , 0x13 ,
317
253
] ) ;
318
254
319
- let bytes = TagBytesRef :: try_from ( bytes. borrow ( ) ) . unwrap ( ) ;
320
- let tag = GenericTag :: ref_from ( bytes) ;
255
+ let tag = GenericTag :: ref_from ( bytes. borrow ( ) ) ;
321
256
let custom_tag = tag. cast :: < CustomDstTag > ( ) ;
322
257
323
258
assert_eq ! ( mem:: size_of_val( custom_tag) , 16 ) ;
@@ -345,10 +280,9 @@ mod tests {
345
280
0 , 0 , 0 , 0 , 0 , 0
346
281
] ,
347
282
) ;
348
- let bytes = TagBytesRef :: try_from ( bytes. borrow ( ) ) . unwrap ( ) ;
349
- let tag = GenericTag :: ref_from ( bytes) ;
350
- assert_eq ! ( tag. header. typ, TagType :: Cmdline ) ;
351
- assert_eq ! ( tag. header. size, 8 + 10 ) ;
283
+ let tag = GenericTag :: ref_from ( bytes. borrow ( ) ) ;
284
+ assert_eq ! ( tag. header( ) . typ, TagType :: Cmdline ) ;
285
+ assert_eq ! ( tag. header( ) . size, 8 + 10 ) ;
352
286
}
353
287
354
288
#[ test]
@@ -367,13 +301,12 @@ mod tests {
367
301
0 , 0 , 0 , 0 , 0 , 0
368
302
] ,
369
303
) ;
370
- let bytes = TagBytesRef :: try_from ( bytes. borrow ( ) ) . unwrap ( ) ;
371
- let tag = GenericTag :: ref_from ( bytes) ;
304
+ let tag = GenericTag :: ref_from ( bytes. borrow ( ) ) ;
372
305
373
306
// Main objective here is also that this test passes Miri.
374
307
let tag = tag. cast :: < GenericTag > ( ) ;
375
- assert_eq ! ( tag. header. typ, TagType :: Cmdline ) ;
376
- assert_eq ! ( tag. header. size, 8 + 10 ) ;
308
+ assert_eq ! ( tag. header( ) . typ, TagType :: Cmdline ) ;
309
+ assert_eq ! ( tag. header( ) . size, 8 + 10 ) ;
377
310
}
378
311
379
312
#[ test]
@@ -397,19 +330,19 @@ mod tests {
397
330
) ;
398
331
let mut iter = TagIter :: new ( bytes. borrow ( ) ) ;
399
332
let first = iter. next ( ) . unwrap ( ) ;
400
- assert_eq ! ( first. header. typ, TagType :: Custom ( 0xff ) ) ;
401
- assert_eq ! ( first. header. size, 8 ) ;
402
- assert ! ( first. payload. is_empty( ) ) ;
333
+ assert_eq ! ( first. header( ) . typ, TagType :: Custom ( 0xff ) ) ;
334
+ assert_eq ! ( first. header( ) . size, 8 ) ;
335
+ assert ! ( first. payload( ) . is_empty( ) ) ;
403
336
404
337
let second = iter. next ( ) . unwrap ( ) ;
405
- assert_eq ! ( second. header. typ, TagType :: Custom ( 0xfe ) ) ;
406
- assert_eq ! ( second. header. size, 12 ) ;
407
- assert_eq ! ( & second. payload, & [ 1 , 2 , 3 , 4 ] ) ;
338
+ assert_eq ! ( second. header( ) . typ, TagType :: Custom ( 0xfe ) ) ;
339
+ assert_eq ! ( second. header( ) . size, 12 ) ;
340
+ assert_eq ! ( & second. payload( ) , & [ 1 , 2 , 3 , 4 ] ) ;
408
341
409
342
let third = iter. next ( ) . unwrap ( ) ;
410
- assert_eq ! ( third. header. typ, TagType :: End ) ;
411
- assert_eq ! ( third. header. size, 8 ) ;
412
- assert ! ( first. payload. is_empty( ) ) ;
343
+ assert_eq ! ( third. header( ) . typ, TagType :: End ) ;
344
+ assert_eq ! ( third. header( ) . size, 8 ) ;
345
+ assert ! ( first. payload( ) . is_empty( ) ) ;
413
346
414
347
assert_eq ! ( iter. next( ) , None ) ;
415
348
}
0 commit comments