Skip to content

Commit 3e0bd0b

Browse files
committed
refactor(test_runner): replace unsafe bitcasts with bytemuck::{cast, bytes_of}
1 parent 9e95e0a commit 3e0bd0b

File tree

3 files changed

+45
-45
lines changed

3 files changed

+45
-45
lines changed

Cargo.lock

Lines changed: 20 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/r3_test_runner/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ serde_json = { version = "1.0.57" }
2222
serialport = { version = "4.0.0" }
2323
itertools = { version = "0.10.0" }
2424
thiserror = { version = "1.0.20" }
25+
bytemuck = { version = "1.12.3", features = ["derive"] }
2526
probe-rs = { version = "0.12.0" }
2627
tempdir = { version = "0.3.7" }
2728
anyhow = { version = "1.0.32" }

src/r3_test_runner/src/targets/rp_pico.rs

Lines changed: 24 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
//! The Pico must first be placed into BOOTSEL mode so that the test runner can
1818
//! load a program.
1919
use anyhow::{anyhow, Context, Result};
20-
use std::future::Future;
20+
use bytemuck::{Pod, Zeroable};
21+
use std::{future::Future, mem::size_of};
2122
use tokio::{
2223
io::{AsyncWriteExt, BufStream},
2324
task::spawn_blocking,
@@ -243,7 +244,7 @@ async fn program_and_run_by_picoboot(exe: &std::path::Path) -> Result<()> {
243244

244245
let hdr = PicobootCmd::new_write(*region_addr as u32, region_data.len() as u32);
245246
let (result, device_handle_tmp) =
246-
write_bulk_all(device_handle, out_endpoint_i, hdr.as_bytes()).await;
247+
write_bulk_all(device_handle, out_endpoint_i, bytemuck::bytes_of(&hdr)).await;
247248
device_handle = device_handle_tmp;
248249
let num_bytes_written = result.with_context(|| "Failed to issue a 'write' command.")?;
249250
if num_bytes_written != 32 {
@@ -274,7 +275,7 @@ async fn program_and_run_by_picoboot(exe: &std::path::Path) -> Result<()> {
274275
);
275276

276277
let hdr = PicobootCmd::new_reboot(loadable_code.entry as u32, 0x2004_2000, 100);
277-
let (result, _) = write_bulk_all(device_handle, out_endpoint_i, hdr.as_bytes()).await;
278+
let (result, _) = write_bulk_all(device_handle, out_endpoint_i, bytemuck::bytes_of(&hdr)).await;
278279
let num_bytes_written = result.with_context(|| "Failed to issue a 'reboot' command.")?;
279280
if num_bytes_written != 32 {
280281
anyhow::bail!("Short write ({} < 32)", num_bytes_written);
@@ -465,41 +466,39 @@ fn open_picoboot() -> Result<PicobootInterface> {
465466
}
466467

467468
#[repr(C)]
468-
#[derive(Clone, Copy)]
469+
#[derive(Clone, Copy, Pod, Zeroable)]
469470
struct PicobootCmd {
470471
_magic: u32,
471472
_token: u32,
472473
_cmd_id: u8,
473474
_cmd_size: u8,
474475
_reserved: u16,
475476
_transfer_length: u32,
476-
_args: PicobootCmdArgs,
477+
/// One of `PicobootCmdArgs*`
478+
_args: [u8; 16],
477479
}
478480

479481
#[repr(C)]
480-
#[derive(Clone, Copy)]
481-
union PicobootCmdArgs {
482-
_reboot: PicobootCmdArgsReboot,
483-
_addr_size: PicobootCmdArgsAddrSize,
484-
}
485-
486-
#[repr(C)]
487-
#[derive(Clone, Copy)]
482+
#[derive(Clone, Copy, Pod, Zeroable)]
488483
struct PicobootCmdArgsAddrSize {
489484
_addr: u32,
490485
_size: u32,
491486
_pad: [u8; 8],
492487
}
493488

494489
#[repr(C)]
495-
#[derive(Clone, Copy)]
490+
#[derive(Clone, Copy, Pod, Zeroable)]
496491
struct PicobootCmdArgsReboot {
497492
_pc: u32,
498493
_sp: u32,
499494
_delay_ms: u32,
500495
_pad: [u8; 4],
501496
}
502497

498+
const _: () = assert!(size_of::<PicobootCmd>() == 32);
499+
const _: () = assert!(size_of::<PicobootCmdArgsAddrSize>() == 16);
500+
const _: () = assert!(size_of::<PicobootCmdArgsReboot>() == 16);
501+
503502
impl PicobootCmd {
504503
/// Writes a contiguous memory range of memory (Flash or RAM) on the RP2040.
505504
fn new_write(addr: u32, size: u32) -> Self {
@@ -510,13 +509,11 @@ impl PicobootCmd {
510509
_cmd_size: 0x08,
511510
_reserved: 0,
512511
_transfer_length: size,
513-
_args: PicobootCmdArgs {
514-
_addr_size: PicobootCmdArgsAddrSize {
515-
_addr: addr,
516-
_size: size,
517-
_pad: [0; _],
518-
},
519-
},
512+
_args: bytemuck::cast(PicobootCmdArgsAddrSize {
513+
_addr: addr,
514+
_size: size,
515+
_pad: [0; _],
516+
}),
520517
}
521518
}
522519

@@ -529,14 +526,12 @@ impl PicobootCmd {
529526
_cmd_size: 0x0c,
530527
_reserved: 0,
531528
_transfer_length: 0,
532-
_args: PicobootCmdArgs {
533-
_reboot: PicobootCmdArgsReboot {
534-
_pc: pc,
535-
_sp: sp,
536-
_delay_ms: delay_ms,
537-
_pad: [0; _],
538-
},
539-
},
529+
_args: bytemuck::cast(PicobootCmdArgsReboot {
530+
_pc: pc,
531+
_sp: sp,
532+
_delay_ms: delay_ms,
533+
_pad: [0; _],
534+
}),
540535
}
541536
}
542537

@@ -549,9 +544,4 @@ impl PicobootCmd {
549544
);
550545
value
551546
}
552-
553-
fn as_bytes(&self) -> &[u8; 32] {
554-
assert_eq!(std::mem::size_of::<Self>(), 32);
555-
unsafe { &*<*const _>::cast(self) }
556-
}
557547
}

0 commit comments

Comments
 (0)