From 3edb8f39dbef06b9e967fa5e6175797bb32c431b Mon Sep 17 00:00:00 2001 From: Renyi Zhao Date: Fri, 5 Sep 2025 20:14:47 +0800 Subject: [PATCH 1/6] glib: Fix misuse of operator in subtract_days --- glib/src/date.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/glib/src/date.rs b/glib/src/date.rs index 39947b99cc1a..83e5cf1de198 100644 --- a/glib/src/date.rs +++ b/glib/src/date.rs @@ -274,7 +274,7 @@ impl Date { #[doc(alias = "g_date_subtract_days")] pub fn subtract_days(&mut self, n_days: u32) -> Result<(), BoolError> { let julian = self.julian(); - if julian > n_days { + if julian < n_days { Err(bool_error!("invalid number of days")) } else { unsafe { From 797269b1d566d296cd26eb5d51e9f8cb086fa7d1 Mon Sep 17 00:00:00 2001 From: Renyi Zhao Date: Fri, 5 Sep 2025 20:17:10 +0800 Subject: [PATCH 2/6] pango: Fix out-of-bounds access in itemize functions --- pango/Gir.toml | 2 ++ pango/src/auto/functions.rs | 48 +--------------------------- pango/src/functions.rs | 64 ++++++++++++++++++++++++++++++++++++- 3 files changed, 66 insertions(+), 48 deletions(-) diff --git a/pango/Gir.toml b/pango/Gir.toml index fe5fc4c608e0..ad5bc0134659 100644 --- a/pango/Gir.toml +++ b/pango/Gir.toml @@ -96,11 +96,13 @@ status = "generate" ignore = true [[object.function]] name = "itemize" + manual = true [[object.function.parameter]] name = "cached_iter" const = true [[object.function]] name = "itemize_with_base_dir" + manual = true [[object.function.parameter]] name = "cached_iter" const = true diff --git a/pango/src/auto/functions.rs b/pango/src/auto/functions.rs index 0f60a789d07b..72f713e40242 100644 --- a/pango/src/auto/functions.rs +++ b/pango/src/auto/functions.rs @@ -2,9 +2,7 @@ // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT -use crate::{ - ffi, AttrIterator, AttrList, Context, Direction, Item, Stretch, Style, Variant, Weight, -}; +use crate::{ffi, AttrList, Direction, Stretch, Style, Variant, Weight}; use glib::translate::*; //#[cfg_attr(feature = "v1_44", deprecated = "Since 1.44")] @@ -56,50 +54,6 @@ pub fn is_zero_width(ch: char) -> bool { unsafe { from_glib(ffi::pango_is_zero_width(ch.into_glib())) } } -#[doc(alias = "pango_itemize")] -pub fn itemize( - context: &Context, - text: &str, - start_index: i32, - length: i32, - attrs: &AttrList, - cached_iter: Option<&AttrIterator>, -) -> Vec { - unsafe { - FromGlibPtrContainer::from_glib_full(ffi::pango_itemize( - context.to_glib_none().0, - text.to_glib_none().0, - start_index, - length, - attrs.to_glib_none().0, - mut_override(cached_iter.to_glib_none().0), - )) - } -} - -#[doc(alias = "pango_itemize_with_base_dir")] -pub fn itemize_with_base_dir( - context: &Context, - base_dir: Direction, - text: &str, - start_index: i32, - length: i32, - attrs: &AttrList, - cached_iter: Option<&AttrIterator>, -) -> Vec { - unsafe { - FromGlibPtrContainer::from_glib_full(ffi::pango_itemize_with_base_dir( - context.to_glib_none().0, - base_dir.into_glib(), - text.to_glib_none().0, - start_index, - length, - attrs.to_glib_none().0, - mut_override(cached_iter.to_glib_none().0), - )) - } -} - #[doc(alias = "pango_markup_parser_finish")] pub fn markup_parser_finish( context: &glib::MarkupParseContext, diff --git a/pango/src/functions.rs b/pango/src/functions.rs index 9452a3515ffc..4e2f231b8241 100644 --- a/pango/src/functions.rs +++ b/pango/src/functions.rs @@ -6,7 +6,7 @@ use std::{ffi::c_char, ptr}; pub use crate::auto::functions::*; #[cfg(feature = "v1_44")] use crate::ShapeFlags; -use crate::{ffi, Analysis, GlyphString, Item}; +use crate::{ffi, Analysis, AttrIterator, AttrList, Context, Direction, GlyphString, Item}; #[doc(alias = "pango_reorder_items")] pub fn reorder_items(logical_items: &glib::List) -> glib::List { @@ -93,3 +93,65 @@ pub fn extents_to_pixels( ffi::pango_extents_to_pixels(inclusive.to_glib_none_mut().0, nearest.to_glib_none_mut().0); } } + +#[doc(alias = "pango_itemize")] +pub fn itemize( + context: &Context, + text: &str, + start_index: i32, + length: i32, + attrs: &AttrList, + cached_iter: Option<&AttrIterator>, +) -> Vec { + let total_length = text.len() as i32; + assert!( + start_index >= 0 && start_index < total_length, + "start_index is out of range" + ); + assert!( + length >= 0 && start_index.checked_add(length).unwrap() < total_length, + "start_index + length is out of range" + ); + unsafe { + FromGlibPtrContainer::from_glib_full(ffi::pango_itemize( + context.to_glib_none().0, + text.to_glib_none().0, + start_index, + length, + attrs.to_glib_none().0, + mut_override(cached_iter.to_glib_none().0), + )) + } +} + +#[doc(alias = "pango_itemize_with_base_dir")] +pub fn itemize_with_base_dir( + context: &Context, + base_dir: Direction, + text: &str, + start_index: i32, + length: i32, + attrs: &AttrList, + cached_iter: Option<&AttrIterator>, +) -> Vec { + let total_length = text.len() as i32; + assert!( + start_index >= 0 && start_index < total_length, + "start_index is out of range" + ); + assert!( + length >= 0 && start_index.checked_add(length).unwrap() < total_length, + "start_index + length is out of range" + ); + unsafe { + FromGlibPtrContainer::from_glib_full(ffi::pango_itemize_with_base_dir( + context.to_glib_none().0, + base_dir.into_glib(), + text.to_glib_none().0, + start_index, + length, + attrs.to_glib_none().0, + mut_override(cached_iter.to_glib_none().0), + )) + } +} From 1473e5cf0bcb8e70940710bb4abc9b7b9f226182 Mon Sep 17 00:00:00 2001 From: Renyi Zhao Date: Fri, 5 Sep 2025 20:18:55 +0800 Subject: [PATCH 3/6] graphene: Fix UB in intersect_triangle by validating t_out before assume_init --- graphene/Gir.toml | 3 +++ graphene/src/auto/ray.rs | 41 +------------------------------- graphene/src/ray.rs | 50 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 53 insertions(+), 41 deletions(-) diff --git a/graphene/Gir.toml b/graphene/Gir.toml index 348249edf9f1..3d1903fd3d4c 100644 --- a/graphene/Gir.toml +++ b/graphene/Gir.toml @@ -375,6 +375,9 @@ boxed_inline = true name = "init_from_vec3" rename = "from_vec3" manual = true # manual proper constructor + [[object.function]] + pattern = "intersect_(box|sphere|triangle)" + manual = true # Handle no intersection cases [[object]] name = "Graphene.Rect" diff --git a/graphene/src/auto/ray.rs b/graphene/src/auto/ray.rs index 1fa2acafb62f..e01b286d8a2e 100644 --- a/graphene/src/auto/ray.rs +++ b/graphene/src/auto/ray.rs @@ -2,7 +2,7 @@ // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT -use crate::{ffi, Box, Plane, Point3D, RayIntersectionKind, Sphere, Triangle, Vec3}; +use crate::{ffi, Box, Plane, Point3D, Sphere, Triangle, Vec3}; use glib::translate::*; glib::wrapper! { @@ -85,45 +85,6 @@ impl Ray { } } - #[doc(alias = "graphene_ray_intersect_box")] - pub fn intersect_box(&self, b: &Box) -> (RayIntersectionKind, f32) { - unsafe { - let mut t_out = std::mem::MaybeUninit::uninit(); - let ret = from_glib(ffi::graphene_ray_intersect_box( - self.to_glib_none().0, - b.to_glib_none().0, - t_out.as_mut_ptr(), - )); - (ret, t_out.assume_init()) - } - } - - #[doc(alias = "graphene_ray_intersect_sphere")] - pub fn intersect_sphere(&self, s: &Sphere) -> (RayIntersectionKind, f32) { - unsafe { - let mut t_out = std::mem::MaybeUninit::uninit(); - let ret = from_glib(ffi::graphene_ray_intersect_sphere( - self.to_glib_none().0, - s.to_glib_none().0, - t_out.as_mut_ptr(), - )); - (ret, t_out.assume_init()) - } - } - - #[doc(alias = "graphene_ray_intersect_triangle")] - pub fn intersect_triangle(&self, t: &Triangle) -> (RayIntersectionKind, f32) { - unsafe { - let mut t_out = std::mem::MaybeUninit::uninit(); - let ret = from_glib(ffi::graphene_ray_intersect_triangle( - self.to_glib_none().0, - t.to_glib_none().0, - t_out.as_mut_ptr(), - )); - (ret, t_out.assume_init()) - } - } - #[doc(alias = "graphene_ray_intersects_box")] pub fn intersects_box(&self, b: &Box) -> bool { unsafe { ffi::graphene_ray_intersects_box(self.to_glib_none().0, b.to_glib_none().0) } diff --git a/graphene/src/ray.rs b/graphene/src/ray.rs index b13ed42024a3..5206dbd24c89 100644 --- a/graphene/src/ray.rs +++ b/graphene/src/ray.rs @@ -4,7 +4,7 @@ use std::fmt; use glib::translate::*; -use crate::{ffi, Point3D, Ray, Vec3}; +use crate::{ffi, Box, Point3D, Ray, RayIntersectionKind, Sphere, Triangle, Vec3}; impl Ray { #[doc(alias = "graphene_ray_init")] @@ -35,6 +35,54 @@ impl Ray { ray } } + + #[doc(alias = "graphene_ray_intersect_box")] + pub fn intersect_box(&self, b: &Box) -> (RayIntersectionKind, Option) { + unsafe { + let mut t_out = std::mem::MaybeUninit::uninit(); + let ret = from_glib(ffi::graphene_ray_intersect_box( + self.to_glib_none().0, + b.to_glib_none().0, + t_out.as_mut_ptr(), + )); + match ret { + RayIntersectionKind::None => (ret, None), + _ => (ret, Some(t_out.assume_init())), + } + } + } + + #[doc(alias = "graphene_ray_intersect_sphere")] + pub fn intersect_sphere(&self, s: &Sphere) -> (RayIntersectionKind, Option) { + unsafe { + let mut t_out = std::mem::MaybeUninit::uninit(); + let ret = from_glib(ffi::graphene_ray_intersect_sphere( + self.to_glib_none().0, + s.to_glib_none().0, + t_out.as_mut_ptr(), + )); + match ret { + RayIntersectionKind::None => (ret, None), + _ => (ret, Some(t_out.assume_init())), + } + } + } + + #[doc(alias = "graphene_ray_intersect_triangle")] + pub fn intersect_triangle(&self, t: &Triangle) -> (RayIntersectionKind, Option) { + unsafe { + let mut t_out = std::mem::MaybeUninit::uninit(); + let ret = from_glib(ffi::graphene_ray_intersect_triangle( + self.to_glib_none().0, + t.to_glib_none().0, + t_out.as_mut_ptr(), + )); + match ret { + RayIntersectionKind::None => (ret, None), + _ => (ret, Some(t_out.assume_init())), + } + } + } } impl fmt::Debug for Ray { From 19682580ed9dfacfeb2cf4869912fd60f3aada7e Mon Sep 17 00:00:00 2001 From: Renyi Zhao Date: Fri, 5 Sep 2025 20:20:03 +0800 Subject: [PATCH 4/6] cairo: Add bounds check for nth in region_get_rectangle to prevent UB --- cairo/src/region.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cairo/src/region.rs b/cairo/src/region.rs index 930a5983dc9e..78e450ce2698 100644 --- a/cairo/src/region.rs +++ b/cairo/src/region.rs @@ -176,6 +176,8 @@ impl Region { #[doc(alias = "get_rectangle")] #[doc(alias = "cairo_region_get_rectangle")] pub fn rectangle(&self, nth: i32) -> RectangleInt { + let total_rectangles = self.num_rectangles(); + assert!(nth >= 0 && nth < total_rectangles, "nth is out of range"); unsafe { let rectangle: RectangleInt = ::std::mem::zeroed(); ffi::cairo_region_get_rectangle(self.0.as_ptr(), nth, rectangle.to_raw_none()); From c9ada1eb2db2f2f935df269e7e21ce67b17e760e Mon Sep 17 00:00:00 2001 From: Renyi Zhao Date: Fri, 5 Sep 2025 20:21:18 +0800 Subject: [PATCH 5/6] cairo: Fix integer overflow in create_for_data's len check --- cairo/src/image_surface.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cairo/src/image_surface.rs b/cairo/src/image_surface.rs index c6d3ddc7d097..3495b8b930d1 100644 --- a/cairo/src/image_surface.rs +++ b/cairo/src/image_surface.rs @@ -64,7 +64,12 @@ impl ImageSurface { (data.as_mut_ptr(), data.len()) }; - assert!(len >= (height * stride) as usize); + assert!(width >= 0, "width must be non-negative"); + assert!(height >= 0, "height must be non-negative"); + assert!(stride >= 0, "stride must be non-negative"); + + // check if there is integer overflow + assert!(len >= height.checked_mul(stride).unwrap() as usize); let result = unsafe { ImageSurface::from_raw_full(ffi::cairo_image_surface_create_for_data( ptr, From e5152343284363b8fdf9aa254160508d8114c8d8 Mon Sep 17 00:00:00 2001 From: Renyi Zhao Date: Fri, 5 Sep 2025 20:22:21 +0800 Subject: [PATCH 6/6] glib: Fix UB in spawn_async_with_pipes by validating success before assume_init --- glib/src/functions.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/glib/src/functions.rs b/glib/src/functions.rs index 37e3dd660d2c..612951fc3d36 100644 --- a/glib/src/functions.rs +++ b/glib/src/functions.rs @@ -179,11 +179,11 @@ pub fn spawn_async_with_pipes< standard_error.as_mut_ptr(), &mut error, ); - let child_pid = from_glib(child_pid.assume_init()); - let standard_input = standard_input.assume_init(); - let standard_output = standard_output.assume_init(); - let standard_error = standard_error.assume_init(); if error.is_null() { + let child_pid = from_glib(child_pid.assume_init()); + let standard_input = standard_input.assume_init(); + let standard_output = standard_output.assume_init(); + let standard_error = standard_error.assume_init(); #[cfg(not(windows))] { Ok((