Skip to content

Commit 2b533d9

Browse files
authored
Merge pull request #789 from Thinkofname/audio-fixes
Audio safety fixes
2 parents 7351450 + a0734fd commit 2b533d9

File tree

1 file changed

+36
-42
lines changed

1 file changed

+36
-42
lines changed

src/sdl2/audio.rs

+36-42
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ use std::ops::{Deref, DerefMut};
6060
use std::path::Path;
6161
use std::marker::PhantomData;
6262
use std::mem;
63-
use std::mem::transmute;
6463
use std::ptr;
6564

6665
use AudioSubsystem;
@@ -209,12 +208,16 @@ pub enum AudioStatus {
209208
impl FromPrimitive for AudioStatus {
210209
fn from_i64(n: i64) -> Option<AudioStatus> {
211210
use self::AudioStatus::*;
212-
let n = n as u32;
213211

214-
Some( match unsafe { transmute::<u32, sys::SDL_AudioStatus>(n) } {
215-
sys::SDL_AudioStatus::SDL_AUDIO_STOPPED => Stopped,
216-
sys::SDL_AudioStatus::SDL_AUDIO_PLAYING => Playing,
217-
sys::SDL_AudioStatus::SDL_AUDIO_PAUSED => Paused,
212+
const STOPPED: i64 = sys::SDL_AudioStatus::SDL_AUDIO_STOPPED as i64;
213+
const PLAYING: i64 = sys::SDL_AudioStatus::SDL_AUDIO_PLAYING as i64;
214+
const PAUSED: i64 = sys::SDL_AudioStatus::SDL_AUDIO_PAUSED as i64;
215+
216+
Some(match n {
217+
STOPPED => Stopped,
218+
PLAYING => Playing,
219+
PAUSED => Paused,
220+
_ => return None,
218221
})
219222
}
220223

@@ -373,13 +376,15 @@ extern "C" fn audio_callback_marshall<CB: AudioCallback>
373376
use std::slice::from_raw_parts_mut;
374377
use std::mem::size_of;
375378
unsafe {
376-
let cb_userdata: &mut CB = &mut *(userdata as *mut CB);
379+
let cb_userdata: &mut Option<CB> = &mut *(userdata as *mut _);
377380
let buf: &mut [CB::Channel] = from_raw_parts_mut(
378381
stream as *mut CB::Channel,
379382
len as usize / size_of::<CB::Channel>()
380383
);
381384

382-
cb_userdata.callback(buf);
385+
if let Some(cb) = cb_userdata {
386+
cb.callback(buf);
387+
}
383388
}
384389
}
385390

@@ -394,14 +399,13 @@ pub struct AudioSpecDesired {
394399
}
395400

396401
impl AudioSpecDesired {
397-
fn convert_to_ll<CB, F, C, S>(freq: F, channels: C, samples: S, userdata: *mut CB) -> sys::SDL_AudioSpec
402+
fn convert_to_ll<CB, F, C, S>(freq: F, channels: C, samples: S, userdata: *mut Option<CB>) -> sys::SDL_AudioSpec
398403
where
399404
CB: AudioCallback,
400405
F: Into<Option<i32>>,
401406
C: Into<Option<u8>>,
402407
S: Into<Option<u16>>,
403408
{
404-
use std::mem::transmute;
405409

406410
let freq = freq.into();
407411
let channels = channels.into();
@@ -413,22 +417,20 @@ impl AudioSpecDesired {
413417

414418
// A value of 0 means "fallback" or "default".
415419

416-
unsafe {
417-
sys::SDL_AudioSpec {
418-
freq: freq.unwrap_or(0),
419-
format: <CB::Channel as AudioFormatNum>::audio_format().to_ll(),
420-
channels: channels.unwrap_or(0),
421-
silence: 0,
422-
samples: samples.unwrap_or(0),
423-
padding: 0,
424-
size: 0,
425-
callback: Some(audio_callback_marshall::<CB>
426-
as extern "C" fn
427-
(arg1: *mut c_void,
428-
arg2: *mut uint8_t,
429-
arg3: c_int)),
430-
userdata: transmute(userdata)
431-
}
420+
sys::SDL_AudioSpec {
421+
freq: freq.unwrap_or(0),
422+
format: <CB::Channel as AudioFormatNum>::audio_format().to_ll(),
423+
channels: channels.unwrap_or(0),
424+
silence: 0,
425+
samples: samples.unwrap_or(0),
426+
padding: 0,
427+
size: 0,
428+
callback: Some(audio_callback_marshall::<CB>
429+
as extern "C" fn
430+
(arg1: *mut c_void,
431+
arg2: *mut uint8_t,
432+
arg3: c_int)),
433+
userdata: userdata as *mut _,
432434
}
433435
}
434436

@@ -596,7 +598,7 @@ pub struct AudioDevice<CB: AudioCallback> {
596598
device_id: AudioDeviceID,
597599
spec: AudioSpec,
598600
/// Store the callback to keep it alive for the entire duration of `AudioDevice`.
599-
userdata: Box<CB>
601+
userdata: Box<Option<CB>>
600602
}
601603

602604
impl<CB: AudioCallback> AudioDevice<CB> {
@@ -607,14 +609,8 @@ impl<CB: AudioCallback> AudioDevice<CB> {
607609
D: Into<Option<&'a str>>,
608610
{
609611

610-
// SDL_OpenAudioDevice needs a userdata pointer, but we can't initialize the
611-
// callback without the obtained AudioSpec.
612-
// Create an uninitialized box that will be initialized after SDL_OpenAudioDevice.
613-
let userdata: *mut CB = unsafe {
614-
let b: Box<CB> = Box::new(mem::uninitialized());
615-
mem::transmute(b)
616-
};
617-
let desired = AudioSpecDesired::convert_to_ll(spec.freq, spec.channels, spec.samples, userdata);
612+
let mut userdata: Box<Option<CB>> = Box::new(None);
613+
let desired = AudioSpecDesired::convert_to_ll(spec.freq, spec.channels, spec.samples, &mut *userdata);
618614

619615
let mut obtained = unsafe { mem::uninitialized::<sys::SDL_AudioSpec>() };
620616
unsafe {
@@ -636,10 +632,8 @@ impl<CB: AudioCallback> AudioDevice<CB> {
636632
id => {
637633
let device_id = AudioDeviceID::PlaybackDevice(id);
638634
let spec = AudioSpec::convert_from_ll(obtained);
639-
let mut userdata: Box<CB> = mem::transmute(userdata);
640635

641-
let garbage = mem::replace(&mut userdata as &mut CB, get_callback(spec));
642-
mem::forget(garbage);
636+
*userdata = Some(get_callback(spec));
643637

644638
Ok(AudioDevice {
645639
subsystem: a.clone(),
@@ -713,7 +707,7 @@ impl<CB: AudioCallback> AudioDevice<CB> {
713707
/// but the callback data will be dropped.
714708
pub fn close_and_get_callback(self) -> CB {
715709
drop(self.device_id);
716-
*self.userdata
710+
self.userdata.expect("Missing callback")
717711
}
718712
}
719713

@@ -725,11 +719,11 @@ pub struct AudioDeviceLockGuard<'a, CB> where CB: AudioCallback, CB: 'a {
725719

726720
impl<'a, CB: AudioCallback> Deref for AudioDeviceLockGuard<'a, CB> {
727721
type Target = CB;
728-
fn deref(&self) -> &CB { &self.device.userdata }
722+
fn deref(&self) -> &CB { (*self.device.userdata).as_ref().expect("Missing callback") }
729723
}
730724

731725
impl<'a, CB: AudioCallback> DerefMut for AudioDeviceLockGuard<'a, CB> {
732-
fn deref_mut(&mut self) -> &mut CB { &mut self.device.userdata }
726+
fn deref_mut(&mut self) -> &mut CB { (*self.device.userdata).as_mut().expect("Missing callback") }
733727
}
734728

735729
impl<'a, CB: AudioCallback> Drop for AudioDeviceLockGuard<'a, CB> {
@@ -835,7 +829,7 @@ mod test {
835829
assert_eq!(new_buffer.len(), new_buffer_expected.len(), "capacity must be exactly equal to twice the original vec size");
836830

837831
// // this has been commented, see https://discourse.libsdl.org/t/change-of-behavior-in-audiocvt-sdl-convertaudio-from-2-0-5-to-2-0-6/24682
838-
// // to maybe re-enable it someday
832+
// // to maybe re-enable it someday
839833
// assert_eq!(new_buffer, new_buffer_expected);
840834
}
841835
}

0 commit comments

Comments
 (0)