Skip to content

Commit 2161c41

Browse files
authored
Merge pull request #158 from rust-osdev/fixes2
multiboot2: create DSTs: hopefully better memory fix
2 parents 1da47a1 + eb71d88 commit 2161c41

File tree

10 files changed

+293
-247
lines changed

10 files changed

+293
-247
lines changed

multiboot2-header/src/builder/header.rs

Lines changed: 73 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use crate::{
88
EntryAddressHeaderTag, EntryEfi32HeaderTag, EntryEfi64HeaderTag, FramebufferHeaderTag,
99
ModuleAlignHeaderTag, Multiboot2BasicHeader, RelocatableHeaderTag,
1010
};
11-
use alloc::boxed::Box;
1211
use alloc::vec::Vec;
1312
use core::mem::size_of;
1413
use core::ops::Deref;
@@ -22,7 +21,7 @@ pub struct HeaderBytes {
2221
// guarantee alignment at the moment.
2322
offset: usize,
2423
structure_len: usize,
25-
bytes: Box<[u8]>,
24+
bytes: Vec<u8>,
2625
}
2726

2827
impl HeaderBytes {
@@ -163,7 +162,7 @@ impl HeaderBuilder {
163162
pub fn build(mut self) -> HeaderBytes {
164163
const ALIGN: usize = 8;
165164

166-
// PHASE 1/3: Prepare Vector
165+
// PHASE 1/2: Prepare Vector
167166

168167
// We allocate more than necessary so that we can ensure an correct
169168
// alignment within this data.
@@ -184,17 +183,9 @@ impl HeaderBuilder {
184183
bytes.extend([0].repeat(offset));
185184

186185
// -----------------------------------------------
187-
// PHASE 2/3: Add Tags
186+
// PHASE 2/2: Add Tags
188187
self.build_add_tags(&mut bytes);
189188

190-
// -----------------------------------------------
191-
// PHASE 3/3: Finalize Vector
192-
193-
// Ensure that the vector has the same length as it's capacity. This is
194-
// important so that miri doesn't complain that the boxed memory is
195-
// smaller than the original allocation.
196-
bytes.extend([0].repeat(bytes.capacity() - bytes.len()));
197-
198189
assert_eq!(
199190
alloc_ptr,
200191
bytes.as_ptr(),
@@ -206,11 +197,6 @@ impl HeaderBuilder {
206197
"The offset to alignment area should be zero."
207198
);
208199

209-
// Construct a box from a vec without `into_boxed_slice`. The latter
210-
// calls `shrink` on the allocator, which might reallocate this memory.
211-
// We don't want that!
212-
let bytes = unsafe { Box::from_raw(bytes.leak()) };
213-
214200
HeaderBytes {
215201
offset,
216202
bytes,
@@ -316,6 +302,42 @@ mod tests {
316302
RelocatableHeaderTagPreference,
317303
};
318304

305+
fn create_builder() -> HeaderBuilder {
306+
let builder = HeaderBuilder::new(HeaderTagISA::I386);
307+
// Multiboot2 basic header + end tag
308+
let mut expected_len = 16 + 8;
309+
assert_eq!(builder.expected_len(), expected_len);
310+
311+
// add information request tag
312+
let ifr_builder =
313+
InformationRequestHeaderTagBuilder::new(HeaderTagFlag::Required).add_irs(&[
314+
MbiTagType::EfiMmap,
315+
MbiTagType::Cmdline,
316+
MbiTagType::ElfSections,
317+
]);
318+
let ifr_tag_size_with_padding = ifr_builder.expected_len() + 4;
319+
assert_eq!(
320+
ifr_tag_size_with_padding % 8,
321+
0,
322+
"the length of the IFR tag with padding must be a multiple of 8"
323+
);
324+
expected_len += ifr_tag_size_with_padding;
325+
let builder = builder.information_request_tag(ifr_builder);
326+
assert_eq!(builder.expected_len(), expected_len);
327+
328+
let builder = builder.relocatable_tag(RelocatableHeaderTag::new(
329+
HeaderTagFlag::Required,
330+
0x1337,
331+
0xdeadbeef,
332+
4096,
333+
RelocatableHeaderTagPreference::None,
334+
));
335+
expected_len += 0x18;
336+
assert_eq!(builder.expected_len(), expected_len);
337+
338+
builder
339+
}
340+
319341
#[test]
320342
fn test_size_or_up_aligned() {
321343
assert_eq!(0, HeaderBuilder::size_or_up_aligned(0));
@@ -324,73 +346,44 @@ mod tests {
324346
assert_eq!(16, HeaderBuilder::size_or_up_aligned(9));
325347
}
326348

349+
/// Test of the `build` method in isolation specifically for miri to check
350+
/// for memory issues.
351+
#[test]
352+
fn test_builder_miri() {
353+
let builder = create_builder();
354+
let expected_len = builder.expected_len();
355+
assert_eq!(builder.build().as_bytes().len(), expected_len);
356+
}
357+
327358
#[test]
328359
fn test_builder() {
329360
// Step 1/2: Build Header
330-
let (mb2_hdr_data, expected_len) = {
331-
let builder = HeaderBuilder::new(HeaderTagISA::I386);
332-
// Multiboot2 basic header + end tag
333-
let mut expected_len = 16 + 8;
334-
assert_eq!(builder.expected_len(), expected_len);
335-
336-
// add information request tag
337-
let ifr_builder = InformationRequestHeaderTagBuilder::new(HeaderTagFlag::Required)
338-
.add_irs(&[
339-
MbiTagType::EfiMmap,
340-
MbiTagType::Cmdline,
341-
MbiTagType::ElfSections,
342-
]);
343-
let ifr_tag_size_with_padding = ifr_builder.expected_len() + 4;
344-
assert_eq!(
345-
ifr_tag_size_with_padding % 8,
346-
0,
347-
"the length of the IFR tag with padding must be a multiple of 8"
348-
);
349-
expected_len += ifr_tag_size_with_padding;
350-
let builder = builder.information_request_tag(ifr_builder);
351-
assert_eq!(builder.expected_len(), expected_len);
352-
353-
let builder = builder.relocatable_tag(RelocatableHeaderTag::new(
354-
HeaderTagFlag::Required,
355-
0x1337,
356-
0xdeadbeef,
357-
4096,
358-
RelocatableHeaderTagPreference::None,
359-
));
360-
expected_len += 0x18;
361-
assert_eq!(builder.expected_len(), expected_len);
362-
363-
println!("builder: {:#?}", builder);
364-
println!("expected_len: {} bytes", builder.expected_len());
365-
366-
(builder.build(), expected_len)
367-
};
368-
369-
assert_eq!(mb2_hdr_data.as_bytes().len(), expected_len);
361+
let mb2_hdr_data = create_builder().build();
370362

371363
// Step 2/2: Test the built Header
372-
{
373-
let mb2_hdr = mb2_hdr_data.as_ptr().cast();
374-
let mb2_hdr = unsafe { Multiboot2Header::load(mb2_hdr) }
375-
.expect("the generated header to be loadable");
376-
println!("{:#?}", mb2_hdr);
377-
assert_eq!(
378-
mb2_hdr.relocatable_tag().unwrap().flags(),
379-
HeaderTagFlag::Required
380-
);
381-
assert_eq!(mb2_hdr.relocatable_tag().unwrap().min_addr(), 0x1337);
382-
assert_eq!(mb2_hdr.relocatable_tag().unwrap().max_addr(), 0xdeadbeef);
383-
assert_eq!(mb2_hdr.relocatable_tag().unwrap().align(), 4096);
384-
assert_eq!(
385-
mb2_hdr.relocatable_tag().unwrap().preference(),
386-
RelocatableHeaderTagPreference::None
387-
);
388-
389-
/* you can write the binary to a file and a tool such as crate "bootinfo"
390-
will be able to fully parse the MB2 header
391-
let mut file = std::file::File::create("mb2_hdr.bin").unwrap();
392-
use std::io::Write;
393-
file.write_all(mb2_hdr_data.as_slice()).unwrap();*/
394-
}
364+
let mb2_hdr = mb2_hdr_data.as_ptr().cast();
365+
let mb2_hdr = unsafe { Multiboot2Header::load(mb2_hdr) }
366+
.expect("the generated header to be loadable");
367+
println!("{:#?}", mb2_hdr);
368+
assert_eq!(
369+
mb2_hdr.relocatable_tag().unwrap().flags(),
370+
HeaderTagFlag::Required
371+
);
372+
assert_eq!(mb2_hdr.relocatable_tag().unwrap().min_addr(), 0x1337);
373+
assert_eq!(mb2_hdr.relocatable_tag().unwrap().max_addr(), 0xdeadbeef);
374+
assert_eq!(mb2_hdr.relocatable_tag().unwrap().align(), 4096);
375+
assert_eq!(
376+
mb2_hdr.relocatable_tag().unwrap().preference(),
377+
RelocatableHeaderTagPreference::None
378+
);
379+
380+
// Printing the header transitively ensures that a lot of stuff works.
381+
println!("{:#?}", mb2_hdr);
382+
383+
/* you can write the binary to a file and a tool such as crate "bootinfo"
384+
will be able to fully parse the MB2 header
385+
let mut file = std::file::File::create("mb2_hdr.bin").unwrap();
386+
use std::io::Write;
387+
file.write_all(mb2_hdr_data.as_slice()).unwrap();*/
395388
}
396389
}

multiboot2/src/boot_loader_name.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use core::str::Utf8Error;
55

66
#[cfg(feature = "builder")]
77
use {
8-
crate::builder::boxed_dst_tag, crate::builder::traits::StructAsBytes, crate::TagType,
9-
alloc::boxed::Box, alloc::vec::Vec,
8+
crate::builder::traits::StructAsBytes, crate::builder::BoxedDst, crate::TagType,
9+
alloc::vec::Vec,
1010
};
1111

1212
const METADATA_SIZE: usize = size_of::<TagTypeId>() + size_of::<u32>();
@@ -23,13 +23,13 @@ pub struct BootLoaderNameTag {
2323

2424
impl BootLoaderNameTag {
2525
#[cfg(feature = "builder")]
26-
pub fn new(name: &str) -> Box<Self> {
26+
pub fn new(name: &str) -> BoxedDst<Self> {
2727
let mut bytes: Vec<_> = name.bytes().collect();
2828
if !bytes.ends_with(&[0]) {
2929
// terminating null-byte
3030
bytes.push(0);
3131
}
32-
boxed_dst_tag(TagType::BootLoaderName, &bytes)
32+
BoxedDst::new(TagType::BootLoaderName, &bytes)
3333
}
3434

3535
/// Reads the name of the bootloader that is booting the kernel as Rust
@@ -119,5 +119,11 @@ mod tests {
119119
let bytes = tag.struct_as_bytes();
120120
assert_eq!(bytes, get_bytes());
121121
assert_eq!(tag.name(), Ok(MSG));
122+
123+
// test also some bigger message
124+
let tag = BootLoaderNameTag::new("AbCdEfGhUjK YEAH");
125+
assert_eq!(tag.name(), Ok("AbCdEfGhUjK YEAH"));
126+
let tag = BootLoaderNameTag::new("AbCdEfGhUjK YEAH".repeat(42).as_str());
127+
assert_eq!(tag.name(), Ok("AbCdEfGhUjK YEAH".repeat(42).as_str()));
122128
}
123129
}

0 commit comments

Comments
 (0)