WaveFormat::parse is a safe function that takes &WAVEFORMATEX (18 bytes), but when wFormatTag == WAVE_FORMAT_EXTENSIBLE and cbSize >= 22 it does
let waveformatextensible: WAVEFORMATEXTENSIBLE = unsafe {
std::ptr::read(std::ptr::from_ref(waveformatex).cast::<WAVEFORMATEXTENSIBLE>())
};
i.e. it reads 40 bytes through a reference that only guarantees 18. The SAFETY comment holds for a header that really sits in front of a WAVEFORMATEXTENSIBLE buffer, but the function signature cannot express that, so safe code can trigger an out-of-bounds read:
use wasapi::WaveFormat;
use windows::Win32::Media::Audio::{WAVEFORMATEX, WAVE_FORMAT_EXTENSIBLE};
let header = WAVEFORMATEX {
wFormatTag: WAVE_FORMAT_EXTENSIBLE as u16,
nChannels: 2,
nSamplesPerSec: 48000,
nAvgBytesPerSec: 384000,
nBlockAlign: 8,
wBitsPerSample: 32,
cbSize: 22,
};
// Reads 22 bytes past the end of `header` (UB in safe code).
let _ = WaveFormat::parse(&header);
(wasapi 0.24.0, src/waveformat.rs, parse.)
Possible fixes, in the order I would prefer them:
- Make it
pub unsafe fn parse(waveformatex: *const WAVEFORMATEX) with the safety contract spelled out (the pointer must address a buffer of at least sizeof(WAVEFORMATEX) + cbSize bytes), and keep the safe entry points as parse_from_blob_bytes(&[u8]) (already there) plus perhaps From<WAVEFORMATEXTENSIBLE>.
- Or keep a safe
parse that only reads the WAVEFORMATEX it was given and returns Err(UnsupportedFormat) for the extensible tag, pointing callers at the byte-slice parser.
For what it is worth, Device::from_raw already carries unsafe in 0.24, so this is the one remaining place where a safe signature hides a pointer-width assumption. I am not using parse in my own code (I go through the byte-slice path), so there is no urgency on my side. This report was drafted with AI assistance and checked against the 0.24.0 source by hand.
WaveFormat::parseis a safe function that takes&WAVEFORMATEX(18 bytes), but whenwFormatTag == WAVE_FORMAT_EXTENSIBLEandcbSize >= 22it doesi.e. it reads 40 bytes through a reference that only guarantees 18. The
SAFETYcomment holds for a header that really sits in front of aWAVEFORMATEXTENSIBLEbuffer, but the function signature cannot express that, so safe code can trigger an out-of-bounds read:(wasapi 0.24.0,
src/waveformat.rs,parse.)Possible fixes, in the order I would prefer them:
pub unsafe fn parse(waveformatex: *const WAVEFORMATEX)with the safety contract spelled out (the pointer must address a buffer of at leastsizeof(WAVEFORMATEX) + cbSizebytes), and keep the safe entry points asparse_from_blob_bytes(&[u8])(already there) plus perhapsFrom<WAVEFORMATEXTENSIBLE>.parsethat only reads theWAVEFORMATEXit was given and returnsErr(UnsupportedFormat)for the extensible tag, pointing callers at the byte-slice parser.For what it is worth,
Device::from_rawalready carriesunsafein 0.24, so this is the one remaining place where a safe signature hides a pointer-width assumption. I am not usingparsein my own code (I go through the byte-slice path), so there is no urgency on my side. This report was drafted with AI assistance and checked against the 0.24.0 source by hand.