@@ -177,3 +177,68 @@ fn client_with_unknown_server_name_fails_to_open() {
177177 err
178178 ) ;
179179}
180+
181+ /// Opens a client whose name is not valid UTF-8. `Client::new` only accepts `&str`, but other
182+ /// processes on the server can use any bytes.
183+ fn open_non_utf8_client ( name : & [ u8 ] ) -> crate :: Client {
184+ let name = std:: ffi:: CString :: new ( name) . unwrap ( ) ;
185+ let mut status = 0 ;
186+ let ptr = unsafe {
187+ jack_sys:: jack_client_open ( name. as_ptr ( ) , jack_sys:: JackNoStartServer , & mut status)
188+ } ;
189+ assert ! ( !ptr. is_null( ) , "jack_client_open failed: {status:#x}" ) ;
190+ unsafe { crate :: Client :: from_raw ( ptr) }
191+ }
192+
193+ #[ test]
194+ fn non_utf8_client_name_is_decoded_lossily ( ) {
195+ let client = open_non_utf8_client ( b"non-utf8-\xff " ) ;
196+ assert_eq ! ( client. name( ) , "non-utf8-\u{fffd} " ) ;
197+ assert_eq ! (
198+ client. name_by_uuid( client. uuid( ) ) . as_deref( ) ,
199+ Some ( "non-utf8-\u{fffd} " )
200+ ) ;
201+ }
202+
203+ #[ test]
204+ fn non_utf8_client_registration_does_not_stop_processing ( ) {
205+ use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
206+ use std:: sync:: { Arc , Mutex } ;
207+
208+ struct Registrations ( Arc < Mutex < Vec < String > > > ) ;
209+ impl crate :: NotificationHandler for Registrations {
210+ fn client_registration ( & mut self , _: & crate :: Client , name : & str , is_registered : bool ) {
211+ if is_registered {
212+ self . 0 . lock ( ) . unwrap ( ) . push ( name. to_string ( ) ) ;
213+ }
214+ }
215+ }
216+
217+ let names = Arc :: new ( Mutex :: new ( Vec :: new ( ) ) ) ;
218+ let cycles = Arc :: new ( AtomicUsize :: new ( 0 ) ) ;
219+ let process = {
220+ let cycles = cycles. clone ( ) ;
221+ crate :: contrib:: ClosureProcessHandler :: new ( move |_, _| {
222+ cycles. fetch_add ( 1 , Ordering :: Relaxed ) ;
223+ crate :: Control :: Continue
224+ } )
225+ } ;
226+ let ( client, _) = crate :: Client :: new ( "" , crate :: ClientOptions :: default ( ) ) . unwrap ( ) ;
227+ let ac = client
228+ . activate_async ( Registrations ( names. clone ( ) ) , process)
229+ . unwrap ( ) ;
230+ std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 100 ) ) ;
231+
232+ let _other = open_non_utf8_client ( b"other-\xfe " ) ;
233+ std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 200 ) ) ;
234+ assert ! (
235+ names. lock( ) . unwrap( ) . iter( ) . any( |n| n == "other-\u{fffd} " ) ,
236+ "{:?}" ,
237+ names. lock( ) . unwrap( )
238+ ) ;
239+
240+ let before = cycles. load ( Ordering :: Relaxed ) ;
241+ std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 200 ) ) ;
242+ assert ! ( cycles. load( Ordering :: Relaxed ) > before) ;
243+ ac. deactivate ( ) . unwrap ( ) ;
244+ }
0 commit comments