From 0145c9ffb9e367d341d6d7cf1631769bafb749e5 Mon Sep 17 00:00:00 2001 From: Nikolay Pultsin Date: Fri, 27 Jun 2025 01:52:06 +0200 Subject: [PATCH 1/3] resvg_render() (C wrapper function) does not crash on incorrect input data --- crates/c-api/ResvgQt.h | 4 +++- crates/c-api/lib.rs | 28 ++++++++++++++++++---------- crates/c-api/resvg.h | 3 ++- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/crates/c-api/ResvgQt.h b/crates/c-api/ResvgQt.h index 91584370..6b5bbc89 100644 --- a/crates/c-api/ResvgQt.h +++ b/crates/c-api/ResvgQt.h @@ -524,7 +524,9 @@ class ResvgRenderer { QImage qImg(svgSize.width(), svgSize.height(), QImage::Format_ARGB32_Premultiplied); qImg.fill(Qt::transparent); - resvg_render(d->tree, ts, qImg.width(), qImg.height(), (char*)qImg.bits()); + if (!resvg_render(d->tree, ts, qImg.width(), qImg.height(), (char*)qImg.bits())) { + return QImage(); + } // resvg renders onto the RGBA canvas, while QImage is ARGB. // std::move is required to call inplace version of rgbSwapped(). diff --git a/crates/c-api/lib.rs b/crates/c-api/lib.rs index bb03cd03..bac40b12 100644 --- a/crates/c-api/lib.rs +++ b/crates/c-api/lib.rs @@ -10,6 +10,7 @@ use std::ffi::CStr; use std::os::raw::c_char; use std::slice; +use std::panic::AssertUnwindSafe; use resvg::tiny_skia; use resvg::usvg; @@ -868,6 +869,7 @@ fn convert_error(e: usvg::Error) -> resvg_error { /// @param height Pixmap height. /// @param pixmap Pixmap data. Should have width*height*4 size and contain /// premultiplied RGBA8888 pixels. +/// @return `true` if the rendering was successful; `false` elsewhere #[no_mangle] pub extern "C" fn resvg_render( tree: *const resvg_render_tree, @@ -875,18 +877,24 @@ pub extern "C" fn resvg_render( width: u32, height: u32, pixmap: *mut c_char, -) { - let tree = unsafe { - assert!(!tree.is_null()); - &*tree - }; +) -> bool { + if tree.is_null() || pixmap.is_null() || width <= 0 || height <= 0 { + return false; + } + + std::panic::catch_unwind(AssertUnwindSafe(|| { + let tree = unsafe { + assert!(!tree.is_null()); + &*tree + }; - let pixmap_len = width as usize * height as usize * tiny_skia::BYTES_PER_PIXEL; - let pixmap: &mut [u8] = - unsafe { std::slice::from_raw_parts_mut(pixmap as *mut u8, pixmap_len) }; - let mut pixmap = tiny_skia::PixmapMut::from_bytes(pixmap, width, height).unwrap(); + let pixmap_len = width as usize * height as usize * tiny_skia::BYTES_PER_PIXEL; + let pixmap: &mut [u8] = + unsafe { std::slice::from_raw_parts_mut(pixmap as *mut u8, pixmap_len) }; + let mut pixmap = tiny_skia::PixmapMut::from_bytes(pixmap, width, height).unwrap(); - resvg::render(&tree.0, transform.to_tiny_skia(), &mut pixmap) + resvg::render(&tree.0, transform.to_tiny_skia(), &mut pixmap) + })).is_ok() } /// @brief Renders a Node by ID onto the image. diff --git a/crates/c-api/resvg.h b/crates/c-api/resvg.h index 126379b0..19bb118b 100644 --- a/crates/c-api/resvg.h +++ b/crates/c-api/resvg.h @@ -481,8 +481,9 @@ void resvg_tree_destroy(resvg_render_tree *tree); * @param height Pixmap height. * @param pixmap Pixmap data. Should have width*height*4 size and contain * premultiplied RGBA8888 pixels. + * @return `true` if the rendering was successful; `false` elsewhere */ -void resvg_render(const resvg_render_tree *tree, +bool resvg_render(const resvg_render_tree *tree, resvg_transform transform, uint32_t width, uint32_t height, From bbaaa164f0ea2068d260a1d2f0c4be2557d63860 Mon Sep 17 00:00:00 2001 From: Nikolay Pultsin Date: Fri, 27 Jun 2025 02:01:23 +0200 Subject: [PATCH 2/3] better formatting --- crates/c-api/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/c-api/lib.rs b/crates/c-api/lib.rs index bac40b12..65d6faa5 100644 --- a/crates/c-api/lib.rs +++ b/crates/c-api/lib.rs @@ -9,8 +9,8 @@ use std::ffi::CStr; use std::os::raw::c_char; -use std::slice; use std::panic::AssertUnwindSafe; +use std::slice; use resvg::tiny_skia; use resvg::usvg; @@ -894,7 +894,8 @@ pub extern "C" fn resvg_render( let mut pixmap = tiny_skia::PixmapMut::from_bytes(pixmap, width, height).unwrap(); resvg::render(&tree.0, transform.to_tiny_skia(), &mut pixmap) - })).is_ok() + })) + .is_ok() } /// @brief Renders a Node by ID onto the image. From e32e06191dcd820388436a5014aff3a990354516 Mon Sep 17 00:00:00 2001 From: Nikolay Pultsin Date: Fri, 27 Jun 2025 17:32:44 +0200 Subject: [PATCH 3/3] unnecessary assert has gone --- crates/c-api/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/c-api/lib.rs b/crates/c-api/lib.rs index 65d6faa5..6e2458bf 100644 --- a/crates/c-api/lib.rs +++ b/crates/c-api/lib.rs @@ -883,10 +883,7 @@ pub extern "C" fn resvg_render( } std::panic::catch_unwind(AssertUnwindSafe(|| { - let tree = unsafe { - assert!(!tree.is_null()); - &*tree - }; + let tree = unsafe { &*tree }; let pixmap_len = width as usize * height as usize * tiny_skia::BYTES_PER_PIXEL; let pixmap: &mut [u8] =