Skip to content

Commit 1cfeb9c

Browse files
kawadakksdroege
authored andcommitted
glib: Null-terminate on every iteration in StrV::extend_from_slice
We need to ensure that `self` is null-terminated even if `<S as AsRef< str>>::as_ref` panics.
1 parent ea62b8f commit 1cfeb9c

File tree

1 file changed

+36
-2
lines changed

1 file changed

+36
-2
lines changed

glib/src/collections/strv.rs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -780,9 +780,11 @@ impl StrV {
780780
for item in other {
781781
*self.ptr.as_ptr().add(self.len) = GString::from(item.as_ref()).into_glib_ptr();
782782
self.len += 1;
783-
}
784783

785-
*self.ptr.as_ptr().add(self.len) = ptr::null_mut();
784+
// Add null terminator on every iteration because `as_ref`
785+
// may panic
786+
*self.ptr.as_ptr().add(self.len) = ptr::null_mut();
787+
}
786788
}
787789
}
788790

@@ -1813,4 +1815,36 @@ mod test {
18131815
// overflow
18141816
strv.extend_from_slice(&[ImplicitStr; usize::MAX - 3]);
18151817
}
1818+
1819+
#[test]
1820+
fn test_extend_from_slice_panic_safe() {
1821+
struct MayPanic(bool);
1822+
1823+
impl AsRef<str> for MayPanic {
1824+
fn as_ref(&self) -> &str {
1825+
if self.0 {
1826+
panic!("panicking as per request");
1827+
} else {
1828+
""
1829+
}
1830+
}
1831+
}
1832+
1833+
let mut strv = StrV::from(&[crate::gstr!(""); 3][..]);
1834+
strv.clear();
1835+
1836+
// Write one element and panic while getting the second element
1837+
_ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1838+
strv.extend_from_slice(&[MayPanic(false), MayPanic(true)]);
1839+
}));
1840+
1841+
// Check that it contains up to one element is null-terminated
1842+
assert!(strv.len() <= 1);
1843+
unsafe {
1844+
for i in 0..strv.len() {
1845+
assert!(!(*strv.as_ptr().add(i)).is_null());
1846+
}
1847+
assert!((*strv.as_ptr().add(strv.len())).is_null());
1848+
}
1849+
}
18161850
}

0 commit comments

Comments
 (0)