From 8d3ada5d8903e646bb46694e5c15523b5c923034 Mon Sep 17 00:00:00 2001 From: Vivia Nikolaidou Date: Sun, 9 Oct 2022 18:28:17 +0300 Subject: [PATCH] pad: Catch panics in pad task functions https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/246 --- gstreamer/src/pad.rs | 67 +++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/gstreamer/src/pad.rs b/gstreamer/src/pad.rs index c18434a6f..4907e4549 100644 --- a/gstreamer/src/pad.rs +++ b/gstreamer/src/pad.rs @@ -1,8 +1,10 @@ // Take a look at the license at the top of the repository in the LICENSE file. +use crate::element::ElementExtManual; use crate::format::{ FormattedValue, SpecificFormattedValueFullRange, SpecificFormattedValueIntrinsic, }; +use crate::prelude::PadExt; use crate::Buffer; use crate::BufferList; use crate::Event; @@ -22,6 +24,7 @@ use crate::{Format, GenericFormattedValue}; use std::mem; use std::num::NonZeroU64; use std::ops::ControlFlow; +use std::panic::{self, AssertUnwindSafe}; use std::ptr; use glib::ffi::gpointer; @@ -709,12 +712,59 @@ impl> PadExtManual for O { } fn start_task(&self, func: F) -> Result<(), glib::BoolError> { + unsafe extern "C" fn trampoline_pad_task(func: gpointer) { + let (func, pad) = &mut *(func as *mut (F, *mut ffi::GstPad)); + let pad = Pad::from_glib_borrow(*pad); + let result = panic::catch_unwind(AssertUnwindSafe(func)); + + if let Err(err) = result { + let element = match pad.parent_element() { + Some(element) => element, + None => panic::resume_unwind(err), + }; + + let maybe_couldnt_stop = if pad.pause_task().is_err() { + ", could not stop task" + } else { + "" + }; + let cause = if let Some(cause) = err.downcast_ref::<&str>() { + cause + } else if let Some(cause) = err.downcast_ref::() { + cause + } else { + "Panicked" + }; + let _ = element.post_message( + crate::message::Error::builder( + crate::LibraryError::Failed, + &format!("Panicked: {}{}", cause, maybe_couldnt_stop), + ) + .src(&*pad) + .build(), + ); + } + } + + fn into_raw_pad_task( + func: F, + pad: *mut ffi::GstPad, + ) -> gpointer { + #[allow(clippy::type_complexity)] + let func: Box<(F, *mut ffi::GstPad)> = Box::new((func, pad)); + Box::into_raw(func) as gpointer + } + + unsafe extern "C" fn destroy_closure_pad_task(ptr: gpointer) { + let _ = Box::<(F, *mut ffi::GstPad)>::from_raw(ptr as *mut _); + } + unsafe { glib::result_from_gboolean!( ffi::gst_pad_start_task( self.as_ref().to_glib_none().0, Some(trampoline_pad_task::), - into_raw_pad_task(func), + into_raw_pad_task(func, self.upcast_ref().as_ptr()), Some(destroy_closure_pad_task::), ), "Failed to start pad task", @@ -1536,21 +1586,6 @@ unsafe extern "C" fn destroy_closure(ptr: gpointer) { let _ = Box::::from_raw(ptr as *mut _); } -unsafe extern "C" fn trampoline_pad_task(func: gpointer) { - let func: &mut F = &mut *(func as *mut F); - func() -} - -fn into_raw_pad_task(func: F) -> gpointer { - #[allow(clippy::type_complexity)] - let func: Box = Box::new(func); - Box::into_raw(func) as gpointer -} - -unsafe extern "C" fn destroy_closure_pad_task(ptr: gpointer) { - let _ = Box::::from_raw(ptr as *mut _); -} - impl Pad { #[doc(alias = "gst_pad_new")] pub fn new(name: Option<&str>, direction: crate::PadDirection) -> Self {