Skip to content

Commit 5fa38ab

Browse files
committed
Don't panic or leak on non-UTF-8 properties
1 parent 4b4f78b commit 5fa38ab

2 files changed

Lines changed: 40 additions & 11 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
- Property types reported as an empty string (as PipeWire does for a missing type) are now
1818
`None` instead of `Some("")`, in `Client::property_get` and `Client::property_get_subject`.
1919
Non-UTF-8 property types no longer panic.
20+
- `Client::property_get`, `property_get_subject` and `property_get_all` no longer panic on
21+
non-UTF-8 keys, values or types. Invalid bytes are replaced with `U+FFFD`.
2022

2123
## 0.9.0
2224

‎src/properties.rs‎

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)