From 729aaf52552054c67f4fbe4d4304415f7c51fc08 Mon Sep 17 00:00:00 2001 From: Nolan Darilek Date: Thu, 10 Mar 2022 11:39:42 -0600 Subject: [PATCH] Soundness fixes for cloning `Connection`. --- speech-dispatcher/examples/clone_drop.rs | 42 +++++++ speech-dispatcher/src/lib.rs | 140 ++++++++++++----------- 2 files changed, 113 insertions(+), 69 deletions(-) create mode 100644 speech-dispatcher/examples/clone_drop.rs diff --git a/speech-dispatcher/examples/clone_drop.rs b/speech-dispatcher/examples/clone_drop.rs new file mode 100644 index 0000000..a86864d --- /dev/null +++ b/speech-dispatcher/examples/clone_drop.rs @@ -0,0 +1,42 @@ +use speech_dispatcher::*; +use std::io; + +fn main() -> Result<(), Box> { + let connection = speech_dispatcher::Connection::open( + "hello_world", + "hello_world", + "hello_world", + Mode::Threaded, + )?; + connection.on_begin(Some(Box::new(|msg_id, client_id| { + println!("Beginning {} from {}", msg_id, client_id) + }))); + connection.on_end(Some(Box::new(|msg_id, client_id| { + println!("Ending {} from {}", msg_id, client_id) + }))); + let connection_clone = connection.clone(); + drop(connection); + connection_clone.say( + Priority::Important, + format!( + "Hello, world at rate {} from client {}.", + connection_clone.get_voice_rate(), + connection_clone.client_id() + ), + ); + connection_clone.set_voice_rate(100)?; + connection_clone.say(Priority::Important, "This is faster."); + connection_clone.set_voice_rate(0)?; + connection_clone.set_spelling(true)?; + connection_clone.say(Priority::Important, "This is spelled."); + connection_clone.set_spelling(false)?; + connection_clone.set_punctuation(Punctuation::All)?; + connection_clone.say( + Priority::Important, + "This statement, unlike others, has punctuation that is spoken!", + ); + connection_clone.set_punctuation(Punctuation::None)?; + let mut _input = String::new(); + io::stdin().read_line(&mut _input).unwrap(); + Ok(()) +} diff --git a/speech-dispatcher/src/lib.rs b/speech-dispatcher/src/lib.rs index a2ea3d0..37f617f 100644 --- a/speech-dispatcher/src/lib.rs +++ b/speech-dispatcher/src/lib.rs @@ -6,7 +6,7 @@ use std::{ fmt, marker::Send, os::raw::{c_char, c_int}, - sync::Mutex, + sync::{Arc, Mutex}, }; use lazy_static::lazy_static; @@ -73,9 +73,6 @@ impl Voice { } } -#[derive(Clone, Debug)] -pub struct Connection(pub *mut SPDConnection, u64); - pub type Address = SPDConnectionAddress; #[derive(Clone, Copy, Debug)] @@ -205,6 +202,9 @@ impl fmt::Display for Error { } } +#[derive(Clone, Debug)] +pub struct Connection(pub Arc<*mut SPDConnection>, u64); + impl Connection { pub fn open>( client_name: S, @@ -228,7 +228,7 @@ impl Connection { Ok(Self::setup_connection(c)) } }; - let mut c = Self(connection?, 0); + let mut c = Self(Arc::new(connection?), 0); c.setup()?; Ok(c) } @@ -262,7 +262,7 @@ impl Connection { Ok(Self::setup_connection(c)) } }; - let mut c = Self(connection?, 0); + let mut c = Self(Arc::new(connection?), 0); c.setup()?; Ok(c) } @@ -298,13 +298,13 @@ impl Connection { } pub fn close(&self) { - unsafe { spd_close(self.0) }; + unsafe { spd_close(*self.0) }; } pub fn say>(&self, priority: Priority, text: S) -> Option { let text: String = text.into(); let param = CString::new(text).unwrap(); - let rv = unsafe { spd_say(self.0, priority as u32, param.as_ptr()) }; + let rv = unsafe { spd_say(*self.0, priority as u32, param.as_ptr()) }; if rv != -1 { Some(rv as u64) } else { @@ -315,7 +315,7 @@ impl Connection { pub fn sayf>(&self, priority: Priority, format: S) -> Option { let format: String = format.into(); let param = CString::new(format).unwrap(); - let rv = unsafe { spd_sayf(self.0, priority as u32, param.as_ptr()) }; + let rv = unsafe { spd_sayf(*self.0, priority as u32, param.as_ptr()) }; if rv != -1 { Some(rv) } else { @@ -324,79 +324,79 @@ impl Connection { } pub fn stop(&self) -> Result<(), Error> { - let v = unsafe { spd_stop(self.0) }; + let v = unsafe { spd_stop(*self.0) }; c_int_to_result(v) } pub fn stop_all(&self) -> Result<(), Error> { - let v = unsafe { spd_stop_all(self.0) }; + let v = unsafe { spd_stop_all(*self.0) }; c_int_to_result(v) } pub fn stop_uid(&self, target_uid: i32) -> Result<(), Error> { - let v = unsafe { spd_stop_uid(self.0, target_uid) }; + let v = unsafe { spd_stop_uid(*self.0, target_uid) }; c_int_to_result(v) } pub fn cancel(&self) -> Result<(), Error> { - let v = unsafe { spd_cancel(self.0) }; + let v = unsafe { spd_cancel(*self.0) }; c_int_to_result(v) } pub fn cancel_all(&self) -> Result<(), Error> { - let v = unsafe { spd_cancel_all(self.0) }; + let v = unsafe { spd_cancel_all(*self.0) }; c_int_to_result(v) } pub fn cancel_uid(&self, target_uid: i32) -> Result<(), Error> { - let v = unsafe { spd_cancel_uid(self.0, target_uid) }; + let v = unsafe { spd_cancel_uid(*self.0, target_uid) }; c_int_to_result(v) } pub fn pause(&self) -> Result<(), Error> { - let v = unsafe { spd_pause(self.0) }; + let v = unsafe { spd_pause(*self.0) }; c_int_to_result(v) } pub fn pause_all(&self) -> Result<(), Error> { - let v = unsafe { spd_pause_all(self.0) }; + let v = unsafe { spd_pause_all(*self.0) }; c_int_to_result(v) } pub fn pause_uid(&self, target_uid: i32) -> Result<(), Error> { - let v = unsafe { spd_pause_uid(self.0, target_uid) }; + let v = unsafe { spd_pause_uid(*self.0, target_uid) }; c_int_to_result(v) } pub fn resume(&self) -> Result<(), Error> { - let v = unsafe { spd_resume(self.0) }; + let v = unsafe { spd_resume(*self.0) }; c_int_to_result(v) } pub fn resume_all(&self) -> Result<(), Error> { - let v = unsafe { spd_resume_all(self.0) }; + let v = unsafe { spd_resume_all(*self.0) }; c_int_to_result(v) } pub fn resume_uid(&self, target_uid: i32) -> Result<(), Error> { - let v = unsafe { spd_resume_uid(self.0, target_uid) }; + let v = unsafe { spd_resume_uid(*self.0, target_uid) }; c_int_to_result(v) } pub fn key>(&self, priority: Priority, key_name: S) -> Result<(), Error> { let param = CString::new(key_name.into()).unwrap(); - let v = unsafe { spd_key(self.0, priority as u32, param.as_ptr()) }; + let v = unsafe { spd_key(*self.0, priority as u32, param.as_ptr()) }; c_int_to_result(v) } pub fn char>(&self, priority: Priority, char: S) -> Result<(), Error> { let param = CString::new(char.into()).unwrap(); - let v = unsafe { spd_char(self.0, priority as u32, param.as_ptr()) }; + let v = unsafe { spd_char(*self.0, priority as u32, param.as_ptr()) }; c_int_to_result(v) } pub fn wchar(&self, priority: Priority, wchar: i32) -> Result<(), Error> { - let v = unsafe { spd_wchar(self.0, priority as u32, wchar as wchar_t) }; + let v = unsafe { spd_wchar(*self.0, priority as u32, wchar as wchar_t) }; c_int_to_result(v) } @@ -406,27 +406,27 @@ impl Connection { icon_name: S, ) -> Result<(), Error> { let param = CString::new(icon_name.into()).unwrap(); - let v = unsafe { spd_char(self.0, priority as u32, param.as_ptr()) }; + let v = unsafe { spd_char(*self.0, priority as u32, param.as_ptr()) }; c_int_to_result(v) } pub fn set_voice_type(&self, voice_type: VoiceType) -> Result<(), Error> { - let v = unsafe { spd_set_voice_type(self.0, voice_type as u32) }; + let v = unsafe { spd_set_voice_type(*self.0, voice_type as u32) }; c_int_to_result(v) } pub fn set_voice_type_all(&self, voice_type: VoiceType) -> Result<(), Error> { - let v = unsafe { spd_set_voice_type_all(self.0, voice_type as u32) }; + let v = unsafe { spd_set_voice_type_all(*self.0, voice_type as u32) }; c_int_to_result(v) } pub fn set_voice_type_uid(&self, voice_type: VoiceType, target_uid: u32) -> Result<(), Error> { - let v = unsafe { spd_set_voice_type_uid(self.0, voice_type as u32, target_uid) }; + let v = unsafe { spd_set_voice_type_uid(*self.0, voice_type as u32, target_uid) }; c_int_to_result(v) } pub fn get_voice_type(&self) -> Result { - let v = unsafe { spd_get_voice_type(self.0) }; + let v = unsafe { spd_get_voice_type(*self.0) }; Ok(match v { SPDVoiceType::SPD_MALE1 => VoiceType::Male1, SPDVoiceType::SPD_MALE2 => VoiceType::Male2, @@ -442,13 +442,13 @@ impl Connection { pub fn set_synthesis_voice(&self, voice: &Voice) -> Result<(), Error> { let param = CString::new(voice.name.clone()).unwrap(); - let v = unsafe { spd_set_synthesis_voice(self.0, param.as_ptr()) }; + let v = unsafe { spd_set_synthesis_voice(*self.0, param.as_ptr()) }; c_int_to_result(v) } pub fn set_synthesis_voice_all>(&self, voice_name: S) -> Result<(), Error> { let param = CString::new(voice_name.into()).unwrap(); - let v = unsafe { spd_set_synthesis_voice_all(self.0, param.as_ptr()) }; + let v = unsafe { spd_set_synthesis_voice_all(*self.0, param.as_ptr()) }; c_int_to_result(v) } @@ -458,22 +458,22 @@ impl Connection { target_uid: u32, ) -> Result<(), Error> { let param = CString::new(voice_name.into()).unwrap(); - let v = unsafe { spd_set_synthesis_voice_uid(self.0, param.as_ptr(), target_uid) }; + let v = unsafe { spd_set_synthesis_voice_uid(*self.0, param.as_ptr(), target_uid) }; c_int_to_result(v) } pub fn set_data_mode(&self, mode: DataMode) -> Result<(), Error> { - let v = unsafe { spd_set_data_mode(self.0, mode as u32) }; + let v = unsafe { spd_set_data_mode(*self.0, mode as u32) }; c_int_to_result(v) } pub fn set_notification_on(&self, notification: Notification) -> Result<(), Error> { - let v = unsafe { spd_set_notification_on(self.0, notification as u32) }; + let v = unsafe { spd_set_notification_on(*self.0, notification as u32) }; c_int_to_result(v) } pub fn set_notification_off(&self, notification: Notification) -> Result<(), Error> { - let v = unsafe { spd_set_notification_off(self.0, notification as u32) }; + let v = unsafe { spd_set_notification_off(*self.0, notification as u32) }; c_int_to_result(v) } @@ -483,74 +483,74 @@ impl Connection { state: S, ) -> Result<(), Error> { let param = CString::new(state.into()).unwrap(); - let v = unsafe { spd_set_notification(self.0, notification as u32, param.as_ptr()) }; + let v = unsafe { spd_set_notification(*self.0, notification as u32, param.as_ptr()) }; c_int_to_result(v) } pub fn set_voice_rate(&self, rate: i32) -> Result<(), Error> { - let v = unsafe { spd_set_voice_rate(self.0, rate) }; + let v = unsafe { spd_set_voice_rate(*self.0, rate) }; c_int_to_result(v) } pub fn set_voice_rate_all(&self, rate: i32) -> Result<(), Error> { - let v = unsafe { spd_set_voice_rate_all(self.0, rate) }; + let v = unsafe { spd_set_voice_rate_all(*self.0, rate) }; c_int_to_result(v) } pub fn set_voice_rate_uid(&self, rate: i32, target_uid: u32) -> Result<(), Error> { - let v = unsafe { spd_set_voice_rate_uid(self.0, rate, target_uid) }; + let v = unsafe { spd_set_voice_rate_uid(*self.0, rate, target_uid) }; c_int_to_result(v) } pub fn get_voice_rate(&self) -> i32 { - unsafe { spd_get_voice_rate(self.0) } + unsafe { spd_get_voice_rate(*self.0) } } pub fn set_voice_pitch(&self, pitch: i32) -> Result<(), Error> { - let v = unsafe { spd_set_voice_pitch(self.0, pitch) }; + let v = unsafe { spd_set_voice_pitch(*self.0, pitch) }; c_int_to_result(v) } pub fn set_voice_pitch_all(&self, pitch: i32) -> Result<(), Error> { - let v = unsafe { spd_set_voice_pitch_all(self.0, pitch) }; + let v = unsafe { spd_set_voice_pitch_all(*self.0, pitch) }; c_int_to_result(v) } pub fn set_voice_pitch_uid(&self, pitch: i32, target_uid: u32) -> Result<(), Error> { - let v = unsafe { spd_set_voice_pitch_uid(self.0, pitch, target_uid) }; + let v = unsafe { spd_set_voice_pitch_uid(*self.0, pitch, target_uid) }; c_int_to_result(v) } pub fn get_voice_pitch(&self) -> i32 { - unsafe { spd_get_voice_pitch(self.0) } + unsafe { spd_get_voice_pitch(*self.0) } } pub fn set_volume(&self, volume: i32) -> Result<(), Error> { - let v = unsafe { spd_set_volume(self.0, volume) }; + let v = unsafe { spd_set_volume(*self.0, volume) }; c_int_to_result(v) } pub fn set_volume_all(&self, volume: i32) -> Result<(), Error> { - let v = unsafe { spd_set_volume_all(self.0, volume) }; + let v = unsafe { spd_set_volume_all(*self.0, volume) }; c_int_to_result(v) } pub fn set_volume_uid(&self, volume: i32, target_uid: u32) -> Result<(), Error> { - let v = unsafe { spd_set_volume_uid(self.0, volume, target_uid) }; + let v = unsafe { spd_set_volume_uid(*self.0, volume, target_uid) }; c_int_to_result(v) } pub fn get_volume(&self) -> i32 { - unsafe { spd_get_volume(self.0) } + unsafe { spd_get_volume(*self.0) } } pub fn set_punctuation(&self, punctuation: Punctuation) -> Result<(), Error> { - let v = unsafe { spd_set_punctuation(self.0, punctuation as u32) }; + let v = unsafe { spd_set_punctuation(*self.0, punctuation as u32) }; c_int_to_result(v) } pub fn set_punctuation_all(&self, punctuation: Punctuation) -> Result<(), Error> { - let v = unsafe { spd_set_punctuation_all(self.0, punctuation as u32) }; + let v = unsafe { spd_set_punctuation_all(*self.0, punctuation as u32) }; c_int_to_result(v) } @@ -559,17 +559,17 @@ impl Connection { punctuation: Punctuation, target_uid: u32, ) -> Result<(), Error> { - let v = unsafe { spd_set_punctuation_uid(self.0, punctuation as u32, target_uid) }; + let v = unsafe { spd_set_punctuation_uid(*self.0, punctuation as u32, target_uid) }; c_int_to_result(v) } pub fn set_capital_letters(&self, capital_letters: CapitalLetters) -> Result<(), Error> { - let v = unsafe { spd_set_capital_letters(self.0, capital_letters as u32) }; + let v = unsafe { spd_set_capital_letters(*self.0, capital_letters as u32) }; c_int_to_result(v) } pub fn set_capital_letters_all(&self, capital_letters: CapitalLetters) -> Result<(), Error> { - let v = unsafe { spd_set_capital_letters_all(self.0, capital_letters as u32) }; + let v = unsafe { spd_set_capital_letters_all(*self.0, capital_letters as u32) }; c_int_to_result(v) } @@ -578,7 +578,7 @@ impl Connection { capital_letters: CapitalLetters, target_uid: u32, ) -> Result<(), Error> { - let v = unsafe { spd_set_capital_letters_uid(self.0, capital_letters as u32, target_uid) }; + let v = unsafe { spd_set_capital_letters_uid(*self.0, capital_letters as u32, target_uid) }; c_int_to_result(v) } @@ -588,7 +588,7 @@ impl Connection { } else { SPDSpelling::SPD_SPELL_OFF }; - let v = unsafe { spd_set_spelling(self.0, s) }; + let v = unsafe { spd_set_spelling(*self.0, s) }; c_int_to_result(v) } @@ -598,7 +598,7 @@ impl Connection { } else { SPDSpelling::SPD_SPELL_OFF }; - let v = unsafe { spd_set_spelling_all(self.0, s) }; + let v = unsafe { spd_set_spelling_all(*self.0, s) }; c_int_to_result(v) } @@ -608,19 +608,19 @@ impl Connection { } else { SPDSpelling::SPD_SPELL_OFF }; - let v = unsafe { spd_set_spelling_uid(self.0, s, target_uid) }; + let v = unsafe { spd_set_spelling_uid(*self.0, s, target_uid) }; c_int_to_result(v) } pub fn set_language>(&self, language: S) -> Result<(), Error> { let param = CString::new(language.into()).unwrap(); - let v = unsafe { spd_set_language(self.0, param.as_ptr()) }; + let v = unsafe { spd_set_language(*self.0, param.as_ptr()) }; c_int_to_result(v) } pub fn set_language_all>(&self, language: S) -> Result<(), Error> { let param = CString::new(language.into()).unwrap(); - let v = unsafe { spd_set_language_all(self.0, param.as_ptr()) }; + let v = unsafe { spd_set_language_all(*self.0, param.as_ptr()) }; c_int_to_result(v) } @@ -630,12 +630,12 @@ impl Connection { target_uid: u32, ) -> Result<(), Error> { let param = CString::new(language.into()).unwrap(); - let v = unsafe { spd_set_language_uid(self.0, param.as_ptr(), target_uid) }; + let v = unsafe { spd_set_language_uid(*self.0, param.as_ptr(), target_uid) }; c_int_to_result(v) } pub fn get_language(&self) -> Result<&str, Error> { - let language = unsafe { spd_get_language(self.0) }; + let language = unsafe { spd_get_language(*self.0) }; if language.is_null() { Err(Error::OperationFailed) } else { @@ -646,13 +646,13 @@ impl Connection { pub fn set_output_module>(&self, output_module: S) -> Result<(), Error> { let param = CString::new(output_module.into()).unwrap(); - let v = unsafe { spd_set_output_module(self.0, param.as_ptr()) }; + let v = unsafe { spd_set_output_module(*self.0, param.as_ptr()) }; c_int_to_result(v) } pub fn set_output_module_all>(&self, output_module: S) -> Result<(), Error> { let param = CString::new(output_module.into()).unwrap(); - let v = unsafe { spd_set_output_module_all(self.0, param.as_ptr()) }; + let v = unsafe { spd_set_output_module_all(*self.0, param.as_ptr()) }; c_int_to_result(v) } @@ -662,7 +662,7 @@ impl Connection { target_uid: u32, ) -> Result<(), Error> { let param = CString::new(output_module.into()).unwrap(); - let v = unsafe { spd_set_output_module_uid(self.0, param.as_ptr(), target_uid) }; + let v = unsafe { spd_set_output_module_uid(*self.0, param.as_ptr(), target_uid) }; c_int_to_result(v) } @@ -673,7 +673,7 @@ impl Connection { SPD_NO_REPLY as i32 }; let data = CString::new(data.into()).unwrap(); - let rv = unsafe { spd_send_data(self.0, data.as_ptr(), wfr) }; + let rv = unsafe { spd_send_data(*self.0, data.as_ptr(), wfr) }; if rv.is_null() { None } else { @@ -737,7 +737,7 @@ impl Connection { } pub fn list_synthesis_voices(&self) -> Result, Error> { - let start = unsafe { spd_list_synthesis_voices(self.0) }; + let start = unsafe { spd_list_synthesis_voices(*self.0) }; let slice = unsafe { null_term_array_ptr_to_slice(start) }.ok_or(Error::OperationFailed)?; let voices = unsafe { slice @@ -759,7 +759,7 @@ impl Connection { } pub fn list_output_modules(&self) -> Result, Error> { - let start = unsafe { spd_list_modules(self.0) }; + let start = unsafe { spd_list_modules(*self.0) }; let slice = unsafe { null_term_array_ptr_to_slice(start) }.ok_or(Error::OperationFailed)?; let modules = unsafe { slice @@ -799,7 +799,9 @@ unsafe impl Send for Connection {} impl Drop for Connection { fn drop(&mut self) { - self.close(); - callbacks.lock().unwrap().remove(&self.1); + if Arc::strong_count(&self.0) <= 1 { + self.close(); + callbacks.lock().unwrap().remove(&self.1); + } } }