@@ -146,18 +146,12 @@ mod metadata {
146146 let properties_slice =
147147 std:: slice:: from_raw_parts ( description. as_ref ( ) . properties , len as usize ) ;
148148 for prop in properties_slice {
149+ // Lossy conversions so that non-UTF-8 data from other clients can't panic and leak
150+ // `description`.
149151 let typ = property_type ( prop. _type ) ;
150152 properties. insert (
151- ffi:: CStr :: from_ptr ( prop. key )
152- . to_str ( )
153- . expect ( "to turn key to str" )
154- . to_string ( ) ,
155- Property :: new (
156- ffi:: CStr :: from_ptr ( prop. data )
157- . to_str ( )
158- . expect ( "to turn data to str" ) ,
159- typ,
160- ) ,
153+ ffi:: CStr :: from_ptr ( prop. key ) . to_string_lossy ( ) . into_owned ( ) ,
154+ Property :: new ( ffi:: CStr :: from_ptr ( prop. data ) . to_string_lossy ( ) , typ) ,
161155 ) ;
162156 }
163157 }
@@ -210,7 +204,7 @@ mod metadata {
210204 let value = value. assume_init ( ) ;
211205 let typ = typ. assume_init ( ) ;
212206 let r = Some ( Property :: new (
213- ffi:: CStr :: from_ptr ( value) . to_str ( ) . unwrap ( ) ,
207+ ffi:: CStr :: from_ptr ( value) . to_string_lossy ( ) ,
214208 property_type ( typ) ,
215209 ) ) ;
216210 j:: jack_free ( value as _ ) ;
@@ -424,6 +418,39 @@ mod metadata {
424418 }
425419 }
426420
421+ #[ test]
422+ fn non_utf8_properties_do_not_panic ( ) {
423+ let ( c, _) = Client :: new ( "non_utf8" , ClientOptions :: default ( ) ) . unwrap ( ) ;
424+ let key = ffi:: CString :: new ( & b"non-utf8-key-\xff " [ ..] ) . unwrap ( ) ;
425+ let value = ffi:: CString :: new ( & b"value-\xfe " [ ..] ) . unwrap ( ) ;
426+ let typ = ffi:: CString :: new ( & b"type-\xfd " [ ..] ) . unwrap ( ) ;
427+ let rc = unsafe {
428+ j:: jack_set_property (
429+ c. raw ( ) ,
430+ c. uuid ( ) ,
431+ key. as_ptr ( ) ,
432+ value. as_ptr ( ) ,
433+ typ. as_ptr ( ) ,
434+ )
435+ } ;
436+ assert_eq ! ( rc, 0 ) ;
437+
438+ let expected = Property :: new ( "value-\u{fffd} " , Some ( "type-\u{fffd} " . into ( ) ) ) ;
439+ assert_eq ! (
440+ c. property_get( c. uuid( ) , "non-utf8-key-\u{fffd} " ) ,
441+ None ,
442+ "the lossy key is not the key that was stored"
443+ ) ;
444+ let sub = c. property_get_subject ( c. uuid ( ) ) ;
445+ assert_eq ! ( sub. get( "non-utf8-key-\u{fffd} " ) , Some ( & expected) ) ;
446+ let all = c. property_get_all ( ) ;
447+ assert_eq ! (
448+ all. get( & c. uuid( ) ) . unwrap( ) . get( "non-utf8-key-\u{fffd} " ) ,
449+ Some ( & expected)
450+ ) ;
451+ unsafe { j:: jack_remove_property ( c. raw ( ) , c. uuid ( ) , key. as_ptr ( ) ) } ;
452+ }
453+
427454 #[ test]
428455 fn can_remove ( ) {
429456 let ( c1, _) = Client :: new ( "client1" , ClientOptions :: default ( ) ) . unwrap ( ) ;
0 commit comments