diff --git a/Cargo.lock b/Cargo.lock index 94061e93ecbf..124c21ca4073 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -113,9 +113,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.29" +version = "1.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" +checksum = "2352e5597e9c544d5e6d9c95190d5d27738ade584fa8db0a16e130e5c2b5296e" dependencies = [ "shlex", ] @@ -165,18 +165,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.41" +version = "4.5.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9" +checksum = "50fd97c9dc2399518aa331917ac6f274280ec5eb34e555dd291899745c48ec6f" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.41" +version = "4.5.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d" +checksum = "c35b5830294e1fa0462034af85cc95225a4cb07092c088c55bda3147cfcd8f65" dependencies = [ "anstyle", "clap_lex", @@ -199,16 +199,16 @@ dependencies = [ [[package]] name = "criterion" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bf7af66b0989381bd0be551bd7cc91912a655a58c6918420c9527b1fd8b4679" +checksum = "e1c047a62b0cc3e145fa84415a3191f628e980b194c2755aa12300a4e6cbd928" dependencies = [ "anes", "cast", "ciborium", "clap", "criterion-plot", - "itertools 0.13.0", + "itertools", "num-traits", "oorandom", "plotters", @@ -222,12 +222,12 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +checksum = "9b1bcc0dc7dfae599d84ad0b1a55f80cde8af3725da8313b528da95ef783e338" dependencies = [ "cast", - "itertools 0.10.5", + "itertools", ] [[package]] @@ -285,9 +285,9 @@ dependencies = [ [[package]] name = "event-listener" -version = "5.4.0" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ "concurrent-queue", "parking", @@ -630,9 +630,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" [[package]] name = "heck" @@ -650,15 +650,6 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.13.0" @@ -929,9 +920,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.13" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ "bitflags", ] @@ -981,15 +972,15 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -1025,9 +1016,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" @@ -1071,9 +1062,9 @@ dependencies = [ [[package]] name = "sdd" -version = "3.0.9" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f5557d2bbddd5afd236ba7856b0e494f5acc7ce805bb0774cc5674b20a06b4" +checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca" [[package]] name = "serde" @@ -1097,9 +1088,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.142" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7" dependencies = [ "itoa", "memchr", @@ -1155,9 +1146,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "slab" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" @@ -1421,6 +1412,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + [[package]] name = "windows-sys" version = "0.52.0" @@ -1445,7 +1442,7 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.2", + "windows-targets 0.53.3", ] [[package]] @@ -1466,10 +1463,11 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.2" +version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ + "windows-link", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", diff --git a/cairo/src/stream.rs b/cairo/src/stream.rs index 743216e32825..e76af68bf236 100644 --- a/cairo/src/stream.rs +++ b/cairo/src/stream.rs @@ -200,7 +200,7 @@ struct MutableCallbackEnvironment { // so code outside of the `catch_unwind` call must never panic. extern "C" fn write_callback( env: *mut c_void, - data: *mut c_uchar, + data: *const c_uchar, length: c_uint, ) -> ffi::cairo_status_t { // This is consistent with the type of `env` in `Surface::_for_stream`. diff --git a/cairo/src/surface_png.rs b/cairo/src/surface_png.rs index 5c6dbc10df34..d5bcdb2f767c 100644 --- a/cairo/src/surface_png.rs +++ b/cairo/src/surface_png.rs @@ -57,7 +57,7 @@ struct WriteEnv<'a, W: 'a + Write> { unsafe extern "C" fn write_func( closure: *mut c_void, - data: *mut u8, + data: *const u8, len: c_uint, ) -> crate::ffi::cairo_status_t { let write_env: &mut WriteEnv = &mut *(closure as *mut WriteEnv); diff --git a/cairo/sys/src/lib.rs b/cairo/sys/src/lib.rs index 28e7b49e3d34..8141400eabcb 100644 --- a/cairo/sys/src/lib.rs +++ b/cairo/sys/src/lib.rs @@ -262,7 +262,7 @@ pub type cairo_destroy_func_t = Option; pub type cairo_read_func_t = Option cairo_status_t>; pub type cairo_write_func_t = - Option cairo_status_t>; + Option cairo_status_t>; #[cfg(feature = "freetype")] #[cfg_attr(docsrs, doc(cfg(feature = "freetype")))] @@ -1523,7 +1523,7 @@ extern "C" { pub fn cairo_script_create_for_stream( write_func: cairo_write_func_t, closure: *mut c_void, - ) -> cairo_status_t; + ) -> *mut cairo_device_t; #[cfg(feature = "script")] #[cfg_attr(docsrs, doc(cfg(feature = "script")))] pub fn cairo_script_from_recording_surface( diff --git a/gdk-pixbuf/src/auto/versions.txt b/gdk-pixbuf/src/auto/versions.txt index 67f2af610909..4e282f2a791c 100644 --- a/gdk-pixbuf/src/auto/versions.txt +++ b/gdk-pixbuf/src/auto/versions.txt @@ -1,2 +1,2 @@ Generated by gir (https://github.com/gtk-rs/gir @ 19ccbbc9a3d1) -from gir-files (https://github.com/gtk-rs/gir-files @ 5c1e490fe50a) +from gir-files (https://github.com/gtk-rs/gir-files @ a79d23cd6a42) diff --git a/gdk-pixbuf/sys/versions.txt b/gdk-pixbuf/sys/versions.txt index 67f2af610909..4e282f2a791c 100644 --- a/gdk-pixbuf/sys/versions.txt +++ b/gdk-pixbuf/sys/versions.txt @@ -1,2 +1,2 @@ Generated by gir (https://github.com/gtk-rs/gir @ 19ccbbc9a3d1) -from gir-files (https://github.com/gtk-rs/gir-files @ 5c1e490fe50a) +from gir-files (https://github.com/gtk-rs/gir-files @ a79d23cd6a42) diff --git a/gio/src/auto/versions.txt b/gio/src/auto/versions.txt index 67f2af610909..4e282f2a791c 100644 --- a/gio/src/auto/versions.txt +++ b/gio/src/auto/versions.txt @@ -1,2 +1,2 @@ Generated by gir (https://github.com/gtk-rs/gir @ 19ccbbc9a3d1) -from gir-files (https://github.com/gtk-rs/gir-files @ 5c1e490fe50a) +from gir-files (https://github.com/gtk-rs/gir-files @ a79d23cd6a42) diff --git a/gio/src/file_descriptor_based.rs b/gio/src/file_descriptor_based.rs index 3a08c0b62a7b..074f14d66fc6 100644 --- a/gio/src/file_descriptor_based.rs +++ b/gio/src/file_descriptor_based.rs @@ -1,12 +1,12 @@ // Take a look at the license at the top of the repository in the LICENSE file. #[cfg(unix)] -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd}; use crate::ffi; use glib::{prelude::*, translate::*}; #[cfg(all(not(unix), docsrs))] -use socket::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use socket::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; glib::wrapper! { #[doc(alias = "GFileDescriptorBased")] @@ -27,6 +27,12 @@ impl AsRawFd for FileDescriptorBased { } } +impl AsFd for FileDescriptorBased { + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) } + } +} + pub trait FileDescriptorBasedExtManual: IsA + 'static { #[doc(alias = "g_file_descriptor_based_get_fd")] #[doc(alias = "get_fd")] diff --git a/gio/src/list_store.rs b/gio/src/list_store.rs index df6108f70db0..b388015153e7 100644 --- a/gio/src/list_store.rs +++ b/gio/src/list_store.rs @@ -150,34 +150,53 @@ impl ListStore { (*func)(&a).into_glib() } - unsafe { - // GIO requires a non-NULL item to be passed in so we're constructing a fake item here. - // See https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3284 + let mut func = equal_func; + let func_obj: &mut (dyn FnMut(&Object) -> bool) = &mut func; + let func_ptr = &func_obj as *const &mut (dyn FnMut(&Object) -> bool) as glib::ffi::gpointer; + let mut position = std::mem::MaybeUninit::uninit(); + + // GIO prior to 2.76 requires a non-NULL item to be passed in so we're constructing a fake item here. + // See https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3284 + #[cfg(not(feature = "v2_76"))] + let result = unsafe { + let g_class: *mut glib::gobject_ffi::GTypeClass = + glib::gobject_ffi::g_type_class_peek(self.item_type().into_glib()) as *mut _; + + // g_class will be `NULL` when no instance of the `item-type` has been created yet. + // See https://github.com/gtk-rs/gtk-rs-core/issues/1767 + if g_class.is_null() { + return None; + } + let item = glib::gobject_ffi::GObject { - g_type_instance: glib::gobject_ffi::GTypeInstance { - g_class: glib::gobject_ffi::g_type_class_peek(self.item_type().into_glib()) - as *mut _, - }, + g_type_instance: glib::gobject_ffi::GTypeInstance { g_class }, ref_count: 1, qdata: std::ptr::null_mut(), }; - let mut func = equal_func; - let func_obj: &mut (dyn FnMut(&Object) -> bool) = &mut func; - let func_ptr = - &func_obj as *const &mut (dyn FnMut(&Object) -> bool) as glib::ffi::gpointer; - let mut position = std::mem::MaybeUninit::uninit(); - - let found = bool::from_glib(ffi::g_list_store_find_with_equal_func_full( + bool::from_glib(ffi::g_list_store_find_with_equal_func_full( self.to_glib_none().0, mut_override(&item as *const _), Some(equal_func_trampoline), func_ptr, position.as_mut_ptr(), - )); + )) + .then(|| position.assume_init()) + }; - found.then(|| position.assume_init()) - } + #[cfg(feature = "v2_76")] + let result = unsafe { + bool::from_glib(ffi::g_list_store_find_with_equal_func_full( + self.to_glib_none().0, + std::ptr::null_mut(), + Some(equal_func_trampoline), + func_ptr, + position.as_mut_ptr(), + )) + .then(|| position.assume_init()) + }; + + result } } diff --git a/gio/sys/versions.txt b/gio/sys/versions.txt index 67f2af610909..4e282f2a791c 100644 --- a/gio/sys/versions.txt +++ b/gio/sys/versions.txt @@ -1,2 +1,2 @@ Generated by gir (https://github.com/gtk-rs/gir @ 19ccbbc9a3d1) -from gir-files (https://github.com/gtk-rs/gir-files @ 5c1e490fe50a) +from gir-files (https://github.com/gtk-rs/gir-files @ a79d23cd6a42) diff --git a/gir-files b/gir-files index 5c1e490fe50a..a79d23cd6a42 160000 --- a/gir-files +++ b/gir-files @@ -1 +1 @@ -Subproject commit 5c1e490fe50a56dae5ee72e39c410aa9d9a0a1ae +Subproject commit a79d23cd6a42a10ed7d2d817b59ab7ebf179f8c9 diff --git a/glib/Cargo.toml b/glib/Cargo.toml index e5f30b2df4d8..97a11ccd7c9b 100644 --- a/glib/Cargo.toml +++ b/glib/Cargo.toml @@ -36,7 +36,7 @@ memchr = "2.7.5" tempfile = "3" gir-format-check.workspace = true trybuild2 = "1" -criterion = "0.6.0" +criterion = "0.7.0" [features] default = ["gio"] @@ -64,6 +64,10 @@ gio = ["gio-sys"] name = "subclass_compiletest" required-features = ["compiletests"] +[[test]] +name = "regex_compiletest" +required-features = ["compiletests"] + [[bench]] name = "gstring" harness = false diff --git a/glib/gobject-sys/versions.txt b/glib/gobject-sys/versions.txt index 67f2af610909..4e282f2a791c 100644 --- a/glib/gobject-sys/versions.txt +++ b/glib/gobject-sys/versions.txt @@ -1,2 +1,2 @@ Generated by gir (https://github.com/gtk-rs/gir @ 19ccbbc9a3d1) -from gir-files (https://github.com/gtk-rs/gir-files @ 5c1e490fe50a) +from gir-files (https://github.com/gtk-rs/gir-files @ a79d23cd6a42) diff --git a/glib/src/auto/versions.txt b/glib/src/auto/versions.txt index 67f2af610909..4e282f2a791c 100644 --- a/glib/src/auto/versions.txt +++ b/glib/src/auto/versions.txt @@ -1,2 +1,2 @@ Generated by gir (https://github.com/gtk-rs/gir @ 19ccbbc9a3d1) -from gir-files (https://github.com/gtk-rs/gir-files @ 5c1e490fe50a) +from gir-files (https://github.com/gtk-rs/gir-files @ a79d23cd6a42) diff --git a/glib/src/collections/list.rs b/glib/src/collections/list.rs index 9ebb7ffd0d6f..2ab8006b9281 100644 --- a/glib/src/collections/list.rs +++ b/glib/src/collections/list.rs @@ -355,7 +355,7 @@ impl List { unsafe { let mut ptr = head.as_ptr(); while !ptr.is_null() { - let item = &*((*ptr).data as *const ffi::gpointer as *const T); + let item = &*(&(*ptr).data as *const ffi::gpointer as *const T); let next = (*ptr).next; if !f(item) { ptr::drop_in_place(&mut (*ptr).data as *mut ffi::gpointer as *mut T); @@ -909,6 +909,12 @@ mod test { let mut list_items = list2.iter().cloned().collect::>(); list_items.reverse(); assert_eq!(&items[1..], &list_items); + + list.reverse(); + let mut list3 = list.clone(); + list3.retain(|item| item.seconds() >= 14.0); + let list_items = list3.iter().cloned().collect::>(); + assert_eq!(&items[2..], &list_items); } #[test] diff --git a/glib/src/collections/ptr_slice.rs b/glib/src/collections/ptr_slice.rs index 32320555dea0..3388c0a1e931 100644 --- a/glib/src/collections/ptr_slice.rs +++ b/glib/src/collections/ptr_slice.rs @@ -713,7 +713,7 @@ impl PtrSlice { #[allow(clippy::int_plus_one)] pub fn reserve(&mut self, additional: usize) { // Nothing new to reserve as there's still enough space - if self.len + additional + 1 <= self.capacity { + if additional < self.capacity - self.len { return; } @@ -788,7 +788,7 @@ impl PtrSlice { #[inline] pub fn extend_from_slice(&mut self, other: &[T]) { // Nothing new to reserve as there's still enough space - if self.len + other.len() + 1 > self.capacity { + if other.len() >= self.capacity - self.len { self.reserve(other.len()); } @@ -796,12 +796,14 @@ impl PtrSlice { for item in other { ptr::write(self.ptr.as_ptr().add(self.len) as *mut T, item.clone()); self.len += 1; - } - ptr::write( - self.ptr.as_ptr().add(self.len), - Ptr::from(ptr::null_mut::<::GlibType>()), - ); + // Add null terminator on every iteration because `clone` + // may panic + ptr::write( + self.ptr.as_ptr().add(self.len), + Ptr::from(ptr::null_mut::<::GlibType>()), + ); + } } } @@ -813,7 +815,7 @@ impl PtrSlice { assert!(index <= self.len); // Nothing new to reserve as there's still enough space - if self.len + 1 + 1 > self.capacity { + if 1 >= self.capacity - self.len { self.reserve(1); } @@ -840,7 +842,7 @@ impl PtrSlice { #[inline] pub fn push(&mut self, item: T) { // Nothing new to reserve as there's still enough space - if self.len + 1 + 1 > self.capacity { + if 1 >= self.capacity - self.len { self.reserve(1); } diff --git a/glib/src/collections/slice.rs b/glib/src/collections/slice.rs index 8dc771c9ef94..93ec467c3545 100644 --- a/glib/src/collections/slice.rs +++ b/glib/src/collections/slice.rs @@ -614,7 +614,7 @@ impl Slice { /// Reserves at least this much additional capacity. pub fn reserve(&mut self, additional: usize) { // Nothing new to reserve as there's still enough space - if self.len + additional <= self.capacity { + if additional <= self.capacity - self.len { return; } @@ -685,7 +685,7 @@ impl Slice { #[inline] pub fn extend_from_slice(&mut self, other: &[T]) { // Nothing new to reserve as there's still enough space - if self.len + other.len() > self.capacity { + if other.len() > self.capacity - self.len { self.reserve(other.len()); } @@ -706,7 +706,7 @@ impl Slice { assert!(index <= self.len); // Nothing new to reserve as there's still enough space - if self.len + 1 > self.capacity { + if 1 > self.capacity - self.len { self.reserve(1); } @@ -729,7 +729,7 @@ impl Slice { #[allow(clippy::int_plus_one)] pub fn push(&mut self, item: T) { // Nothing new to reserve as there's still enough space - if self.len + 1 > self.capacity { + if 1 > self.capacity - self.len { self.reserve(1); } diff --git a/glib/src/collections/slist.rs b/glib/src/collections/slist.rs index ad1ef90ba2a6..7316145bf9b2 100644 --- a/glib/src/collections/slist.rs +++ b/glib/src/collections/slist.rs @@ -350,7 +350,7 @@ impl SList { unsafe { let mut ptr = head.as_ptr(); while !ptr.is_null() { - let item = &*((*ptr).data as *const ffi::gpointer as *const T); + let item = &*(&(*ptr).data as *const ffi::gpointer as *const T); let next = (*ptr).next; if !f(item) { ptr::drop_in_place(&mut (*ptr).data as *mut ffi::gpointer as *mut T); @@ -902,6 +902,12 @@ mod test { let mut list_items = list2.iter().cloned().collect::>(); list_items.reverse(); assert_eq!(&items[1..], &list_items); + + list.reverse(); + let mut list3 = list.clone(); + list3.retain(|item| item.seconds() >= 14.0); + let list_items = list3.iter().cloned().collect::>(); + assert_eq!(&items[2..], &list_items); } #[test] diff --git a/glib/src/collections/strv.rs b/glib/src/collections/strv.rs index 9451c050edeb..3789840fd02b 100644 --- a/glib/src/collections/strv.rs +++ b/glib/src/collections/strv.rs @@ -65,6 +65,10 @@ impl std::hash::Hash for StrV { impl PartialEq<[&'_ str]> for StrV { fn eq(&self, other: &[&'_ str]) -> bool { + if self.len() != other.len() { + return false; + } + for (a, b) in Iterator::zip(self.iter(), other.iter()) { if a != b { return false; @@ -712,7 +716,7 @@ impl StrV { #[allow(clippy::int_plus_one)] pub fn reserve(&mut self, additional: usize) { // Nothing new to reserve as there's still enough space - if self.len + additional + 1 <= self.capacity { + if additional < self.capacity - self.len { return; } @@ -772,7 +776,7 @@ impl StrV { #[inline] pub fn extend_from_slice>(&mut self, other: &[S]) { // Nothing new to reserve as there's still enough space - if self.len + other.len() + 1 > self.capacity { + if other.len() >= self.capacity - self.len { self.reserve(other.len()); } @@ -780,9 +784,11 @@ impl StrV { for item in other { *self.ptr.as_ptr().add(self.len) = GString::from(item.as_ref()).into_glib_ptr(); self.len += 1; - } - *self.ptr.as_ptr().add(self.len) = ptr::null_mut(); + // Add null terminator on every iteration because `as_ref` + // may panic + *self.ptr.as_ptr().add(self.len) = ptr::null_mut(); + } } } @@ -794,7 +800,7 @@ impl StrV { assert!(index <= self.len); // Nothing new to reserve as there's still enough space - if self.len + 1 + 1 > self.capacity { + if 1 >= self.capacity - self.len { self.reserve(1); } @@ -818,7 +824,7 @@ impl StrV { #[inline] pub fn push(&mut self, item: GString) { // Nothing new to reserve as there's still enough space - if self.len + 1 + 1 > self.capacity { + if 1 >= self.capacity - self.len { self.reserve(1); } @@ -1464,6 +1470,10 @@ impl std::hash::Hash for StrVRef { impl PartialEq<[&'_ str]> for StrVRef { fn eq(&self, other: &[&'_ str]) -> bool { + if self.len() != other.len() { + return false; + } + for (a, b) in Iterator::zip(self.iter(), other.iter()) { if a != b { return false; @@ -1598,6 +1608,7 @@ mod test { StrV::from_glib_full_num(ptr, 4, false) }; + assert_eq!(items.len(), slice.len()); for (a, b) in Iterator::zip(items.iter(), slice.iter()) { assert_eq!(a, b); } @@ -1622,6 +1633,7 @@ mod test { StrV::from_glib_container_num(ptr, 4, false) }; + assert_eq!(items.len(), slice.len()); for (a, b) in Iterator::zip(items.iter(), slice.iter()) { assert_eq!(a, b); } @@ -1648,6 +1660,7 @@ mod test { res }; + assert_eq!(items.len(), slice.len()); for (a, b) in Iterator::zip(items.iter(), slice.iter()) { assert_eq!(a, b); } @@ -1781,4 +1794,80 @@ mod test { assert!(strv.contains("str2")); assert!(!strv.contains("str4")); } + + #[test] + #[should_panic] + fn test_reserve_overflow() { + let mut strv = StrV::from(&[crate::gstr!("foo"); 3][..]); + + // An old implementation of `reserve` used the condition `self.len + + // additional + 1 <= self.capacity`, which was prone to overflow + strv.reserve(usize::MAX - 3); + } + + #[test] + #[should_panic] + fn test_extend_from_slice_overflow() { + // We need a zero-sized type because only a slice of ZST can legally + // contain up to `usize::MAX` elements. + #[derive(Clone, Copy)] + struct ImplicitStr; + + impl AsRef for ImplicitStr { + fn as_ref(&self) -> &str { + "" + } + } + + let mut strv = StrV::from(&[crate::gstr!(""); 3][..]); + + // An old implementation of `extend_from_slice` used the condition + // `self.len + other.len() + 1 <= self.capacity`, which was prone to + // overflow + strv.extend_from_slice(&[ImplicitStr; usize::MAX - 3]); + } + + #[test] + fn test_extend_from_slice_panic_safe() { + struct MayPanic(bool); + + impl AsRef for MayPanic { + fn as_ref(&self) -> &str { + if self.0 { + panic!("panicking as per request"); + } else { + "" + } + } + } + + let mut strv = StrV::from(&[crate::gstr!(""); 3][..]); + strv.clear(); + + // Write one element and panic while getting the second element + _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + strv.extend_from_slice(&[MayPanic(false), MayPanic(true)]); + })); + + // Check that it contains up to one element is null-terminated + assert!(strv.len() <= 1); + unsafe { + for i in 0..strv.len() { + assert!(!(*strv.as_ptr().add(i)).is_null()); + } + assert!((*strv.as_ptr().add(strv.len())).is_null()); + } + } + + #[test] + fn test_strv_ref_eq_str_slice() { + let strv = StrV::from(&[crate::gstr!("a")][..]); + let strv_ref: &StrVRef = strv.as_ref(); + + // Test `impl PartialEq<[&'_ str]> for StrVRef` + assert_eq!(strv_ref, &["a"][..]); + assert_ne!(strv_ref, &[][..]); + assert_ne!(strv_ref, &["a", "b"][..]); + assert_ne!(strv_ref, &["b"][..]); + } } diff --git a/glib/src/thread_guard.rs b/glib/src/thread_guard.rs index bdc511d9b846..3e1dcb9a26c2 100644 --- a/glib/src/thread_guard.rs +++ b/glib/src/thread_guard.rs @@ -1,7 +1,7 @@ // Take a look at the license at the top of the repository in the LICENSE file. use std::{ - mem, ptr, + mem::ManuallyDrop, sync::atomic::{AtomicUsize, Ordering}, }; fn next_thread_id() -> usize { @@ -23,7 +23,9 @@ pub fn thread_id() -> usize { /// Thread guard that only gives access to the contained value on the thread it was created on. pub struct ThreadGuard { thread_id: usize, - value: T, + // This is a `ManuallyDrop` so that the automatic drop glue does not drop `T` + // if this `ThreadGuard` is dropped on the wrong thread. + value: ManuallyDrop, } impl ThreadGuard { @@ -38,7 +40,7 @@ impl ThreadGuard { pub fn new(value: T) -> Self { Self { thread_id: thread_id(), - value, + value: ManuallyDrop::new(value), } } @@ -85,12 +87,16 @@ impl ThreadGuard { /// created. #[inline] pub fn into_inner(self) -> T { + // We wrap `self` in `ManuallyDrop` to defuse `ThreadGuard`'s `Drop` impl. + let mut this = ManuallyDrop::new(self); + assert!( - self.thread_id == thread_id(), + this.thread_id == thread_id(), "Value accessed from different thread than where it was created" ); - unsafe { ptr::read(&mem::ManuallyDrop::new(self).value) } + // SAFETY: We are on the right thread, and this.value will not be touched after this + unsafe { ManuallyDrop::take(&mut this.value) } } // rustdoc-stripper-ignore-next @@ -108,6 +114,9 @@ impl Drop for ThreadGuard { self.thread_id == thread_id(), "Value dropped on a different thread than where it was created" ); + + // SAFETY: We are on the right thread, and self.value will not be touched after this + unsafe { ManuallyDrop::drop(&mut self.value) } } } diff --git a/glib/src/value_array.rs b/glib/src/value_array.rs index b214ad4f3eec..3051e1872c09 100644 --- a/glib/src/value_array.rs +++ b/glib/src/value_array.rs @@ -118,7 +118,7 @@ impl ValueArray { b: ffi::gconstpointer, func: ffi::gpointer, ) -> i32 { - let func = func as *mut &mut (dyn FnMut(&Value, &Value) -> Ordering); + let func = func as *mut &mut dyn FnMut(&Value, &Value) -> Ordering; let a = &*(a as *const Value); let b = &*(b as *const Value); @@ -127,9 +127,9 @@ impl ValueArray { } unsafe { let mut func = compare_func; - let func_obj: &mut (dyn FnMut(&Value, &Value) -> Ordering) = &mut func; + let func_obj: &mut dyn FnMut(&Value, &Value) -> Ordering = &mut func; let func_ptr = - &func_obj as *const &mut (dyn FnMut(&Value, &Value) -> Ordering) as ffi::gpointer; + &func_obj as *const &mut dyn FnMut(&Value, &Value) -> Ordering as ffi::gpointer; gobject_ffi::g_value_array_sort_with_data( self.to_glib_none_mut().0, diff --git a/glib/sys/versions.txt b/glib/sys/versions.txt index 67f2af610909..4e282f2a791c 100644 --- a/glib/sys/versions.txt +++ b/glib/sys/versions.txt @@ -1,2 +1,2 @@ Generated by gir (https://github.com/gtk-rs/gir @ 19ccbbc9a3d1) -from gir-files (https://github.com/gtk-rs/gir-files @ 5c1e490fe50a) +from gir-files (https://github.com/gtk-rs/gir-files @ a79d23cd6a42) diff --git a/graphene/src/auto/versions.txt b/graphene/src/auto/versions.txt index 67f2af610909..4e282f2a791c 100644 --- a/graphene/src/auto/versions.txt +++ b/graphene/src/auto/versions.txt @@ -1,2 +1,2 @@ Generated by gir (https://github.com/gtk-rs/gir @ 19ccbbc9a3d1) -from gir-files (https://github.com/gtk-rs/gir-files @ 5c1e490fe50a) +from gir-files (https://github.com/gtk-rs/gir-files @ a79d23cd6a42) diff --git a/graphene/sys/versions.txt b/graphene/sys/versions.txt index 67f2af610909..4e282f2a791c 100644 --- a/graphene/sys/versions.txt +++ b/graphene/sys/versions.txt @@ -1,2 +1,2 @@ Generated by gir (https://github.com/gtk-rs/gir @ 19ccbbc9a3d1) -from gir-files (https://github.com/gtk-rs/gir-files @ 5c1e490fe50a) +from gir-files (https://github.com/gtk-rs/gir-files @ a79d23cd6a42) diff --git a/pango/src/auto/versions.txt b/pango/src/auto/versions.txt index 67f2af610909..4e282f2a791c 100644 --- a/pango/src/auto/versions.txt +++ b/pango/src/auto/versions.txt @@ -1,2 +1,2 @@ Generated by gir (https://github.com/gtk-rs/gir @ 19ccbbc9a3d1) -from gir-files (https://github.com/gtk-rs/gir-files @ 5c1e490fe50a) +from gir-files (https://github.com/gtk-rs/gir-files @ a79d23cd6a42) diff --git a/pango/sys/versions.txt b/pango/sys/versions.txt index 67f2af610909..4e282f2a791c 100644 --- a/pango/sys/versions.txt +++ b/pango/sys/versions.txt @@ -1,2 +1,2 @@ Generated by gir (https://github.com/gtk-rs/gir @ 19ccbbc9a3d1) -from gir-files (https://github.com/gtk-rs/gir-files @ 5c1e490fe50a) +from gir-files (https://github.com/gtk-rs/gir-files @ a79d23cd6a42) diff --git a/pangocairo/src/auto/versions.txt b/pangocairo/src/auto/versions.txt index 67f2af610909..4e282f2a791c 100644 --- a/pangocairo/src/auto/versions.txt +++ b/pangocairo/src/auto/versions.txt @@ -1,2 +1,2 @@ Generated by gir (https://github.com/gtk-rs/gir @ 19ccbbc9a3d1) -from gir-files (https://github.com/gtk-rs/gir-files @ 5c1e490fe50a) +from gir-files (https://github.com/gtk-rs/gir-files @ a79d23cd6a42) diff --git a/pangocairo/sys/versions.txt b/pangocairo/sys/versions.txt index 67f2af610909..4e282f2a791c 100644 --- a/pangocairo/sys/versions.txt +++ b/pangocairo/sys/versions.txt @@ -1,2 +1,2 @@ Generated by gir (https://github.com/gtk-rs/gir @ 19ccbbc9a3d1) -from gir-files (https://github.com/gtk-rs/gir-files @ 5c1e490fe50a) +from gir-files (https://github.com/gtk-rs/gir-files @ a79d23cd6a42)