I have the following struct which I receive via ffi
#[repr(C)] #[derive(Clone, Copy)] pub struct CDROM_TOC { pub Length: [u8; 2], pub FirstTrack: u8, pub LastTrack: u8, pub TrackData: [TRACK_DATA; 100], } #[repr(C)] #[derive(Clone, Copy)] pub struct TRACK_DATA { pub Reserved: u8, pub _bitfield: u8, pub TrackNumber: u8, pub Reserved1: u8, pub Address: [u8; 4], } I then store this in:
pub struct CdDrive { path: PathBuf, handle: DriveHandle, toc: CDROM_TOC, } For testing & debug purposes I want to dump the TOC as hex:
/// Obtain an array of raw bytes representing the [`CDROM_TOC`] impl CdDrive { pub fn toc_as_raw_bytes(&self) -> &[u8] { let toc: CDROM_TOC = self.toc; // SAFETY check: stored value is the expected size, nothing has changed in the ffi spec const { assert!(size_of::<CDROM_TOC>() == TOC_SIZE) }; // SAFETY: toc.Length Indicates the length, in bytes, of the table of contents data. // This length value does not include the length of the Length member itself. let len = u16::from_be_bytes(toc.Length) .strict_cast::<usize>() .strict_add(size_of_val(&toc.Length)); dbg!(len); assert!(len <= TOC_SIZE); #[expect(unsafe_code, reason = "need to construct slice from raw parts")] unsafe { // SAFETY: correct size validated above std::slice::from_raw_parts(&toc as *const _ as *const _, len) } } /// Obtain a hex representation of the raw bytes representing the [`CDROM_TOC`] pub fn toc_as_hex(&self) -> String { hex_dump(self.toc_as_raw_bytes()) } /// Obtain a reference to the TOC as a [`CDROM_TOC`] pub fn toc(&self) -> &CDROM_TOC { &self.toc } } Every time I call CdDrive::toc_as_hex() for a very specific input I get different results for the mid-section of TrackData.
When I perform the same hex dump on the CDROM_TOC as soon as I receive it, before storing in a CdDrive, I always get the same, valid & correct data.
Initially I that by using a repr(Rust) struct as the outer type I was somehow breaking the repr(c) layout guarantees for the deeply nested data...
However, the location of the difference is consistent on all invocations. It's always tracks 3..=6 and this is likely to be deliberate - this is from a CD from the time where attempts were made to be deliberately incompatible with standards as a form of copy protection.
What I still don't understand, though, is how a data struct stored in memory can provide different output from the code above. So, I'm pretty sure there is something wrong with my approach as well and I'd really like to understand what it is...
For completeness here is an example set of output:
always consistent Length 00 4a Track1 01 LastTr 08 before storing in CdDrive r bf tn r1[ address ] 00 10 01 00 00 00 00 00 00 10 02 00 00 00 ac f0 00 10 03 00 00 01 06 1e 00 10 04 00 00 01 58 56 00 10 05 00 00 01 a4 69 00 10 06 00 00 02 03 aa 00 10 07 00 00 02 98 79 00 10 08 00 00 03 31 c6 00 10 aa 00 00 03 7f 0c first dump from CdDrive 00 10 01 00 00 00 00 00 00 10 02 00 00 00 ac f0 00 10 78 8d 6f 76 35 00 00 00 8a 8b 6f 76 35 00 00 00 d6 8b 6f 76 35 00 00 00 f6 57 a9 8b f6 7f 00 00 07 00 00 02 98 79 00 10 08 00 00 03 31 c6 00 10 aa 00 00 03 7f 0c second dump from CdDrive 00 10 01 00 00 00 00 00 00 10 02 00 00 00 ac f0 00 10 b8 65 6f 76 35 00 00 00 ca 63 6f 76 35 00 00 00 16 64 6f 76 35 00 00 00 f6 57 a9 8b f6 7f 00 00 07 00 00 02 98 79 00 10 08 00 00 03 31 c6 00 10 aa 00 00 03 7f 0c 2 posts - 2 participants



