VYPR
High severityNVD Advisory· Published Dec 26, 2021· Updated Aug 5, 2024

CVE-2019-25055

CVE-2019-25055

Description

An issue was discovered in the libpulse-binding crate before 2.6.0 for Rust. It mishandles a panic that crosses a Foreign Function Interface (FFI) boundary.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

The libpulse-binding Rust crate before 2.6.0 fails to catch panics crossing FFI boundaries, causing undefined behavior.

Vulnerability

The libpulse-binding crate (versions prior to 2.6.0) for Rust contains a flaw where panics that occur inside callbacks passed to PulseAudio's C API are not caught before crossing the FFI boundary. This is a form of undefined behavior (UB) because Rust panics must not propagate into C code. The affected code paths include callback proxies such as get_sink_info_list_cb_proxy and get_source_info_list_cb_proxy, which invoke user-provided callbacks without wrapping them in std::panic::catch_unwind. [1][4]

Exploitation

An attacker would need to trigger a panic inside a callback that is invoked by the PulseAudio library. This could be achieved by providing a callback that panics under certain conditions (e.g., via a malicious or crafted input). The attacker does not require network access or authentication if they can control the callback logic (e.g., in a library consumer's code). The panic propagates across the FFI boundary, leading to undefined behavior. [1]

Impact

Successful exploitation results in undefined behavior, which may manifest as memory corruption, program crashes, or other unpredictable outcomes. The Rust compiler's safety guarantees are violated, potentially allowing an attacker to cause a denial of service or, in worst-case scenarios, arbitrary code execution depending on the specific UB. [4]

Mitigation

The issue is fixed in version 2.6.0 of the libpulse-binding crate, released on or after the commit date (March 2019). Users should update to >=2.6.0. No workarounds are documented; the fix involves wrapping callback invocations with std::panic::catch_unwind to safely handle panics. [1][4]

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
libpulse-bindingcrates.io
< 2.6.02.6.0

Affected products

2

Patches

1
7fd282aef778

use `catch_unwind` with callbacks

https://github.com/jnqnfe/pulse-binding-rustLyndon BrownDec 29, 2018via ghsa
15 files changed · +252 175
  • pulse-binding/CHANGELOG.md+4 0 modified
    @@ -1,3 +1,7 @@
    +# ??? (???, ??, ????)
    +
    + * Implemented use of `std::panic::catch_unwind` in callbacks
    +
     # 2.5.0 (December 22nd, 2018)
     
     **Note: This includes a security fix!**
    
  • pulse-binding/src/context/ext_device_manager.rs+12 9 modified
    @@ -15,6 +15,7 @@
     
     //! Routines for controlling module-device-manager.
     
    +use std;
     use capi;
     use std::ffi::{CStr, CString};
     use std::borrow::Cow;
    @@ -308,13 +309,15 @@ extern "C"
     fn read_list_cb_proxy(_: *mut ContextInternal, i: *const InfoInternal, eol: i32,
         userdata: *mut c_void)
     {
    -    match callback_for_list_instance::<dyn FnMut(ListResult<&Info>)>(eol, userdata) {
    -        ListInstanceCallback::Entry(callback) => {
    -            assert!(!i.is_null());
    -            let obj = Info::new_from_raw(i);
    -            callback(ListResult::Item(&obj));
    -        },
    -        ListInstanceCallback::End(mut callback) => { callback(ListResult::End); },
    -        ListInstanceCallback::Error(mut callback) => { callback(ListResult::Error); },
    -    }
    +    let _ = std::panic::catch_unwind(|| {
    +        match callback_for_list_instance::<dyn FnMut(ListResult<&Info>)>(eol, userdata) {
    +            ListInstanceCallback::Entry(callback) => {
    +                assert!(!i.is_null());
    +                let obj = Info::new_from_raw(i);
    +                (callback)(ListResult::Item(&obj));
    +            },
    +            ListInstanceCallback::End(mut callback) => { (callback)(ListResult::End); },
    +            ListInstanceCallback::Error(mut callback) => { (callback)(ListResult::Error); },
    +        }
    +    });
     }
    
  • pulse-binding/src/context/ext_device_restore.rs+15 11 modified
    @@ -208,8 +208,10 @@ extern "C"
     fn ext_subscribe_cb_proxy(_: *mut ContextInternal, type_: ::def::Device, index: u32,
         userdata: *mut c_void)
     {
    -    let callback = SubscribeCb::get_callback(userdata);
    -    callback(type_, index);
    +    let _ = std::panic::catch_unwind(|| {
    +        let callback = SubscribeCb::get_callback(userdata);
    +        (callback)(type_, index);
    +    });
     }
     
     /// Proxy for read list callbacks.
    @@ -218,13 +220,15 @@ extern "C"
     fn read_list_cb_proxy(_: *mut ContextInternal, i: *const InfoInternal, eol: i32,
         userdata: *mut c_void)
     {
    -    match callback_for_list_instance::<dyn FnMut(ListResult<&Info>)>(eol, userdata) {
    -        ListInstanceCallback::Entry(callback) => {
    -            assert!(!i.is_null());
    -            let obj = Info::new_from_raw(i);
    -            callback(ListResult::Item(&obj));
    -        },
    -        ListInstanceCallback::End(mut callback) => { callback(ListResult::End); },
    -        ListInstanceCallback::Error(mut callback) => { callback(ListResult::Error); },
    -    }
    +    let _ = std::panic::catch_unwind(|| {
    +        match callback_for_list_instance::<dyn FnMut(ListResult<&Info>)>(eol, userdata) {
    +            ListInstanceCallback::Entry(callback) => {
    +                assert!(!i.is_null());
    +                let obj = Info::new_from_raw(i);
    +                (callback)(ListResult::Item(&obj));
    +            },
    +            ListInstanceCallback::End(mut callback) => { (callback)(ListResult::End); },
    +            ListInstanceCallback::Error(mut callback) => { (callback)(ListResult::Error); },
    +        }
    +    });
     }
    
  • pulse-binding/src/context/ext_stream_restore.rs+11 9 modified
    @@ -214,13 +214,15 @@ extern "C"
     fn read_list_cb_proxy(_: *mut ContextInternal, i: *const InfoInternal, eol: i32,
         userdata: *mut c_void)
     {
    -    match callback_for_list_instance::<dyn FnMut(ListResult<&Info>)>(eol, userdata) {
    -        ListInstanceCallback::Entry(callback) => {
    -            assert!(!i.is_null());
    -            let obj = Info::new_from_raw(i);
    -            callback(ListResult::Item(&obj));
    -        },
    -        ListInstanceCallback::End(mut callback) => { callback(ListResult::End); },
    -        ListInstanceCallback::Error(mut callback) => { callback(ListResult::Error); },
    -    }
    +    let _ = std::panic::catch_unwind(|| {
    +        match callback_for_list_instance::<dyn FnMut(ListResult<&Info>)>(eol, userdata) {
    +            ListInstanceCallback::Entry(callback) => {
    +                assert!(!i.is_null());
    +                let obj = Info::new_from_raw(i);
    +                (callback)(ListResult::Item(&obj));
    +            },
    +            ListInstanceCallback::End(mut callback) => { (callback)(ListResult::End); },
    +            ListInstanceCallback::Error(mut callback) => { (callback)(ListResult::Error); },
    +        }
    +    });
     }
    
  • pulse-binding/src/context/introspect.rs+107 85 modified
    @@ -652,15 +652,17 @@ extern "C"
     fn get_sink_info_list_cb_proxy(_: *mut ContextInternal, i: *const SinkInfoInternal, eol: i32,
         userdata: *mut c_void)
     {
    -    match callback_for_list_instance::<dyn FnMut(ListResult<&SinkInfo>)>(eol, userdata) {
    -        ListInstanceCallback::Entry(callback) => {
    -            assert!(!i.is_null());
    -            let obj = SinkInfo::new_from_raw(i);
    -            callback(ListResult::Item(&obj));
    -        },
    -        ListInstanceCallback::End(mut callback) => { callback(ListResult::End); },
    -        ListInstanceCallback::Error(mut callback) => { callback(ListResult::Error); },
    -    }
    +    let _ = std::panic::catch_unwind(|| {
    +        match callback_for_list_instance::<dyn FnMut(ListResult<&SinkInfo>)>(eol, userdata) {
    +            ListInstanceCallback::Entry(callback) => {
    +                assert!(!i.is_null());
    +                let obj = SinkInfo::new_from_raw(i);
    +                (callback)(ListResult::Item(&obj));
    +            },
    +            ListInstanceCallback::End(mut callback) => { (callback)(ListResult::End); },
    +            ListInstanceCallback::Error(mut callback) => { (callback)(ListResult::Error); },
    +        }
    +    });
     }
     
     ////////////////////////////////////////////////////////////////////////////////////////////////////
    @@ -1036,15 +1038,17 @@ extern "C"
     fn get_source_info_list_cb_proxy(_: *mut ContextInternal, i: *const SourceInfoInternal, eol: i32,
         userdata: *mut c_void)
     {
    -    match callback_for_list_instance::<dyn FnMut(ListResult<&SourceInfo>)>(eol, userdata) {
    -        ListInstanceCallback::Entry(callback) => {
    -            assert!(!i.is_null());
    -            let obj = SourceInfo::new_from_raw(i);
    -            callback(ListResult::Item(&obj));
    -        },
    -        ListInstanceCallback::End(mut callback) => { callback(ListResult::End); },
    -        ListInstanceCallback::Error(mut callback) => { callback(ListResult::Error); },
    -    }
    +    let _ = std::panic::catch_unwind(|| {
    +        match callback_for_list_instance::<dyn FnMut(ListResult<&SourceInfo>)>(eol, userdata) {
    +            ListInstanceCallback::Entry(callback) => {
    +                assert!(!i.is_null());
    +                let obj = SourceInfo::new_from_raw(i);
    +                (callback)(ListResult::Item(&obj));
    +            },
    +            ListInstanceCallback::End(mut callback) => { (callback)(ListResult::End); },
    +            ListInstanceCallback::Error(mut callback) => { (callback)(ListResult::Error); },
    +        }
    +    });
     }
     
     ////////////////////////////////////////////////////////////////////////////////////////////////////
    @@ -1136,12 +1140,14 @@ extern "C"
     fn get_server_info_cb_proxy(_: *mut ContextInternal, i: *const ServerInfoInternal,
         userdata: *mut c_void)
     {
    -    assert!(!i.is_null());
    -    let obj = ServerInfo::new_from_raw(i);
    -
    -    // Note, destroys closure callback after use - restoring outer box means it gets dropped
    -    let mut callback = ::callbacks::get_su_callback::<dyn FnMut(&ServerInfo)>(userdata);
    -    callback(&obj);
    +    let _ = std::panic::catch_unwind(|| {
    +        assert!(!i.is_null());
    +        let obj = ServerInfo::new_from_raw(i);
    +
    +        // Note, destroys closure callback after use - restoring outer box means it gets dropped
    +        let mut callback = ::callbacks::get_su_callback::<dyn FnMut(&ServerInfo)>(userdata);
    +        (callback)(&obj);
    +    });
     }
     
     ////////////////////////////////////////////////////////////////////////////////////////////////////
    @@ -1262,24 +1268,28 @@ extern "C"
     fn mod_info_list_cb_proxy(_: *mut ContextInternal, i: *const ModuleInfoInternal, eol: i32,
         userdata: *mut c_void)
     {
    -    match callback_for_list_instance::<dyn FnMut(ListResult<&ModuleInfo>)>(eol, userdata) {
    -        ListInstanceCallback::Entry(callback) => {
    -            assert!(!i.is_null());
    -            let obj = ModuleInfo::new_from_raw(i);
    -            callback(ListResult::Item(&obj));
    -        },
    -        ListInstanceCallback::End(mut callback) => { callback(ListResult::End); },
    -        ListInstanceCallback::Error(mut callback) => { callback(ListResult::Error); },
    -    }
    +    let _ = std::panic::catch_unwind(|| {
    +        match callback_for_list_instance::<dyn FnMut(ListResult<&ModuleInfo>)>(eol, userdata) {
    +            ListInstanceCallback::Entry(callback) => {
    +                assert!(!i.is_null());
    +                let obj = ModuleInfo::new_from_raw(i);
    +                (callback)(ListResult::Item(&obj));
    +            },
    +            ListInstanceCallback::End(mut callback) => { (callback)(ListResult::End); },
    +            ListInstanceCallback::Error(mut callback) => { (callback)(ListResult::Error); },
    +        }
    +    });
     }
     
     /// Proxy for context index callbacks.
     /// Warning: This is for single-use cases only! It destroys the actual closure callback.
     extern "C"
     fn context_index_cb_proxy(_: *mut ContextInternal, index: u32, userdata: *mut c_void) {
    -    // Note, destroys closure callback after use - restoring outer box means it gets dropped
    -    let mut callback = ::callbacks::get_su_callback::<dyn FnMut(u32)>(userdata);
    -    callback(index);
    +    let _ = std::panic::catch_unwind(|| {
    +        // Note, destroys closure callback after use - restoring outer box means it gets dropped
    +        let mut callback = ::callbacks::get_su_callback::<dyn FnMut(u32)>(userdata);
    +        (callback)(index);
    +    });
     }
     
     ////////////////////////////////////////////////////////////////////////////////////////////////////
    @@ -1380,15 +1390,17 @@ extern "C"
     fn get_client_info_list_cb_proxy(_: *mut ContextInternal, i: *const ClientInfoInternal, eol: i32,
         userdata: *mut c_void)
     {
    -    match callback_for_list_instance::<dyn FnMut(ListResult<&ClientInfo>)>(eol, userdata) {
    -        ListInstanceCallback::Entry(callback) => {
    -            assert!(!i.is_null());
    -            let obj = ClientInfo::new_from_raw(i);
    -            callback(ListResult::Item(&obj));
    -        },
    -        ListInstanceCallback::End(mut callback) => { callback(ListResult::End); },
    -        ListInstanceCallback::Error(mut callback) => { callback(ListResult::Error); },
    -    }
    +    let _ = std::panic::catch_unwind(|| {
    +        match callback_for_list_instance::<dyn FnMut(ListResult<&ClientInfo>)>(eol, userdata) {
    +            ListInstanceCallback::Entry(callback) => {
    +                assert!(!i.is_null());
    +                let obj = ClientInfo::new_from_raw(i);
    +                (callback)(ListResult::Item(&obj));
    +            },
    +            ListInstanceCallback::End(mut callback) => { (callback)(ListResult::End); },
    +            ListInstanceCallback::Error(mut callback) => { (callback)(ListResult::Error); },
    +        }
    +    });
     }
     
     ////////////////////////////////////////////////////////////////////////////////////////////////////
    @@ -1690,15 +1702,17 @@ extern "C"
     fn get_card_info_list_cb_proxy(_: *mut ContextInternal, i: *const CardInfoInternal, eol: i32,
         userdata: *mut c_void)
     {
    -    match callback_for_list_instance::<dyn FnMut(ListResult<&CardInfo>)>(eol, userdata) {
    -        ListInstanceCallback::Entry(callback) => {
    -            assert!(!i.is_null());
    -            let obj = CardInfo::new_from_raw(i);
    -            callback(ListResult::Item(&obj));
    -        },
    -        ListInstanceCallback::End(mut callback) => { callback(ListResult::End); },
    -        ListInstanceCallback::Error(mut callback) => { callback(ListResult::Error); },
    -    }
    +    let _ = std::panic::catch_unwind(|| {
    +        match callback_for_list_instance::<dyn FnMut(ListResult<&CardInfo>)>(eol, userdata) {
    +            ListInstanceCallback::Entry(callback) => {
    +                assert!(!i.is_null());
    +                let obj = CardInfo::new_from_raw(i);
    +                (callback)(ListResult::Item(&obj));
    +            },
    +            ListInstanceCallback::End(mut callback) => { (callback)(ListResult::End); },
    +            ListInstanceCallback::Error(mut callback) => { (callback)(ListResult::Error); },
    +        }
    +    });
     }
     
     ////////////////////////////////////////////////////////////////////////////////////////////////////
    @@ -1919,15 +1933,17 @@ extern "C"
     fn get_sink_input_info_list_cb_proxy(_: *mut ContextInternal, i: *const SinkInputInfoInternal,
         eol: i32, userdata: *mut c_void)
     {
    -    match callback_for_list_instance::<dyn FnMut(ListResult<&SinkInputInfo>)>(eol, userdata) {
    -        ListInstanceCallback::Entry(callback) => {
    -            assert!(!i.is_null());
    -            let obj = SinkInputInfo::new_from_raw(i);
    -            callback(ListResult::Item(&obj));
    -        },
    -        ListInstanceCallback::End(mut callback) => { callback(ListResult::End); },
    -        ListInstanceCallback::Error(mut callback) => { callback(ListResult::Error); },
    -    }
    +    let _ = std::panic::catch_unwind(|| {
    +        match callback_for_list_instance::<dyn FnMut(ListResult<&SinkInputInfo>)>(eol, userdata) {
    +            ListInstanceCallback::Entry(callback) => {
    +                assert!(!i.is_null());
    +                let obj = SinkInputInfo::new_from_raw(i);
    +                (callback)(ListResult::Item(&obj));
    +            },
    +            ListInstanceCallback::End(mut callback) => { (callback)(ListResult::End); },
    +            ListInstanceCallback::Error(mut callback) => { (callback)(ListResult::Error); },
    +        }
    +    });
     }
     
     ////////////////////////////////////////////////////////////////////////////////////////////////////
    @@ -2148,15 +2164,17 @@ extern "C"
     fn get_source_output_info_list_cb_proxy(_: *mut ContextInternal, i: *const SourceOutputInfoInternal,
         eol: i32, userdata: *mut c_void)
     {
    -    match callback_for_list_instance::<dyn FnMut(ListResult<&SourceOutputInfo>)>(eol, userdata) {
    -        ListInstanceCallback::Entry(callback) => {
    -            assert!(!i.is_null());
    -            let obj = SourceOutputInfo::new_from_raw(i);
    -            callback(ListResult::Item(&obj));
    -        },
    -        ListInstanceCallback::End(mut callback) => { callback(ListResult::End); },
    -        ListInstanceCallback::Error(mut callback) => { callback(ListResult::Error); },
    -    }
    +    let _ = std::panic::catch_unwind(|| {
    +        match callback_for_list_instance::<dyn FnMut(ListResult<&SourceOutputInfo>)>(eol, userdata) {
    +            ListInstanceCallback::Entry(callback) => {
    +                assert!(!i.is_null());
    +                let obj = SourceOutputInfo::new_from_raw(i);
    +                (callback)(ListResult::Item(&obj));
    +            },
    +            ListInstanceCallback::End(mut callback) => { (callback)(ListResult::End); },
    +            ListInstanceCallback::Error(mut callback) => { (callback)(ListResult::Error); },
    +        }
    +    });
     }
     
     ////////////////////////////////////////////////////////////////////////////////////////////////////
    @@ -2182,10 +2200,12 @@ impl Introspector {
     /// Warning: This is for single-use cases only! It destroys the actual closure callback.
     extern "C"
     fn get_stat_info_cb_proxy(_: *mut ContextInternal, i: *const StatInfo, userdata: *mut c_void) {
    -    assert!(!i.is_null());
    -    // Note, destroys closure callback after use - restoring outer box means it gets dropped
    -    let mut callback = ::callbacks::get_su_callback::<dyn FnMut(&StatInfo)>(userdata);
    -    callback(unsafe { i.as_ref().unwrap() });
    +    let _ = std::panic::catch_unwind(|| {
    +        assert!(!i.is_null());
    +        // Note, destroys closure callback after use - restoring outer box means it gets dropped
    +        let mut callback = ::callbacks::get_su_callback::<dyn FnMut(&StatInfo)>(userdata);
    +        (callback)(unsafe { i.as_ref().unwrap() });
    +    });
     }
     
     ////////////////////////////////////////////////////////////////////////////////////////////////////
    @@ -2301,13 +2321,15 @@ extern "C"
     fn get_sample_info_list_cb_proxy(_: *mut ContextInternal, i: *const SampleInfoInternal, eol: i32,
         userdata: *mut c_void)
     {
    -    match callback_for_list_instance::<dyn FnMut(ListResult<&SampleInfo>)>(eol, userdata) {
    -        ListInstanceCallback::Entry(callback) => {
    -            assert!(!i.is_null());
    -            let obj = SampleInfo::new_from_raw(i);
    -            callback(ListResult::Item(&obj));
    -        },
    -        ListInstanceCallback::End(mut callback) => { callback(ListResult::End); },
    -        ListInstanceCallback::Error(mut callback) => { callback(ListResult::Error); },
    -    }
    +    let _ = std::panic::catch_unwind(|| {
    +        match callback_for_list_instance::<dyn FnMut(ListResult<&SampleInfo>)>(eol, userdata) {
    +            ListInstanceCallback::Entry(callback) => {
    +                assert!(!i.is_null());
    +                let obj = SampleInfo::new_from_raw(i);
    +                (callback)(ListResult::Item(&obj));
    +            },
    +            ListInstanceCallback::End(mut callback) => { (callback)(ListResult::End); },
    +            ListInstanceCallback::Error(mut callback) => { (callback)(ListResult::Error); },
    +        }
    +    });
     }
    
  • pulse-binding/src/context/mod.rs+36 24 modified
    @@ -599,30 +599,36 @@ impl Drop for Context {
     /// Warning: This is for single-use cases only! It destroys the actual closure callback.
     extern "C"
     fn success_cb_proxy(_: *mut ContextInternal, success: i32, userdata: *mut c_void) {
    -    assert!(!userdata.is_null());
    -    // Note, destroys closure callback after use - restoring outer box means it gets dropped
    -    let mut callback = unsafe { Box::from_raw(userdata as *mut Box<dyn FnMut(bool)>) };
         let success_actual = match success { 0 => false, _ => true };
    -    callback(success_actual);
    +    let _ = std::panic::catch_unwind(|| {
    +        assert!(!userdata.is_null());
    +        // Note, destroys closure callback after use - restoring outer box means it gets dropped
    +        let mut callback = unsafe { Box::from_raw(userdata as *mut Box<dyn FnMut(bool)>) };
    +        (callback)(success_actual);
    +    });
     }
     
     /// Proxy for notification callbacks (single use).
     /// Warning: This is for single-use cases only! It destroys the actual closure callback.
     extern "C"
     fn notify_cb_proxy_single(_: *mut ContextInternal, userdata: *mut c_void) {
    -    assert!(!userdata.is_null());
    -    // Note, destroys closure callback after use - restoring outer box means it gets dropped
    -    let mut callback = unsafe { Box::from_raw(userdata as *mut Box<dyn FnMut()>) };
    -    callback();
    +    let _ = std::panic::catch_unwind(|| {
    +        assert!(!userdata.is_null());
    +        // Note, destroys closure callback after use - restoring outer box means it gets dropped
    +        let mut callback = unsafe { Box::from_raw(userdata as *mut Box<dyn FnMut()>) };
    +        (callback)();
    +    });
     }
     
     /// Proxy for notification callbacks (multi use).
     /// Warning: This is for multi-use cases! It does **not** destroy the actual closure callback, which
     /// must be accomplished separately to avoid a memory leak.
     extern "C"
     fn notify_cb_proxy_multi(_: *mut ContextInternal, userdata: *mut c_void) {
    -    let callback = NotifyCb::get_callback(userdata);
    -    callback();
    +    let _ = std::panic::catch_unwind(|| {
    +        let callback = NotifyCb::get_callback(userdata);
    +        (callback)();
    +    });
     }
     
     /// Proxy for event callbacks.
    @@ -632,31 +638,37 @@ extern "C"
     fn event_cb_proxy(_: *mut ContextInternal, name: *const c_char,
         proplist: *mut ::proplist::ProplistInternal, userdata: *mut c_void)
     {
    -    assert!(!name.is_null());
    -    let n = {
    -        let tmp = unsafe { CStr::from_ptr(name) };
    -        tmp.to_string_lossy().into_owned()
    -    };
    -    let pl = Proplist::from_raw_weak(proplist);
    -
    -    let callback = EventCb::get_callback(userdata);
    -    callback(n, pl);
    +    let _ = std::panic::catch_unwind(|| {
    +        assert!(!name.is_null());
    +        let n = {
    +            let tmp = unsafe { CStr::from_ptr(name) };
    +            tmp.to_string_lossy().into_owned()
    +        };
    +        let pl = Proplist::from_raw_weak(proplist);
    +
    +        let callback = EventCb::get_callback(userdata);
    +        (callback)(n, pl);
    +    });
     }
     
     /// Proxy for extension test callbacks.
     /// Warning: This is for single-use cases only! It destroys the actual closure callback.
     extern "C"
     fn ext_test_cb_proxy(_: *mut ContextInternal, version: u32, userdata: *mut c_void) {
    -    // Note, destroys closure callback after use - restoring outer box means it gets dropped
    -    let mut callback = ::callbacks::get_su_callback::<dyn FnMut(u32)>(userdata);
    -    callback(version);
    +    let _ = std::panic::catch_unwind(|| {
    +        // Note, destroys closure callback after use - restoring outer box means it gets dropped
    +        let mut callback = ::callbacks::get_su_callback::<dyn FnMut(u32)>(userdata);
    +        (callback)(version);
    +    });
     }
     
     /// Proxy for extension subscribe callbacks.
     /// Warning: This is for multi-use cases! It does **not** destroy the actual closure callback, which
     /// must be accomplished separately to avoid a memory leak.
     extern "C"
     fn ext_subscribe_cb_proxy(_: *mut ContextInternal, userdata: *mut c_void) {
    -    let callback = ExtSubscribeCb::get_callback(userdata);
    -    callback();
    +    let _ = std::panic::catch_unwind(|| {
    +        let callback = ExtSubscribeCb::get_callback(userdata);
    +        (callback)();
    +    });
     }
    
  • pulse-binding/src/context/scache.rs+6 4 modified
    @@ -62,6 +62,7 @@
     //! [`::context::Context::play_sample`]: ../struct.Context.html#method.play_sample
     //! [`::context::Context::remove_sample`]: ../struct.Context.html#method.remove_sample
     
    +use std;
     use capi;
     use std::os::raw::{c_char, c_void};
     use std::ffi::CString;
    @@ -187,8 +188,9 @@ impl Context {
     extern "C"
     fn play_sample_success_cb_proxy(_: *mut ContextInternal, index: u32, userdata: *mut c_void) {
         let index_actual = match index { ::def::INVALID_INDEX => Err(()), i => Ok(i) };
    -
    -    // Note, destroys closure callback after use - restoring outer box means it gets dropped
    -    let mut callback = ::callbacks::get_su_callback::<dyn FnMut(Result<u32, ()>)>(userdata);
    -    callback(index_actual);
    +    let _ = std::panic::catch_unwind(|| {
    +        // Note, destroys closure callback after use - restoring outer box means it gets dropped
    +        let mut callback = ::callbacks::get_su_callback::<dyn FnMut(Result<u32, ()>)>(userdata);
    +        (callback)(index_actual);
    +    });
     }
    
  • pulse-binding/src/context/subscribe.rs+7 4 modified
    @@ -56,6 +56,7 @@
     //! [`::context::Context::set_subscribe_callback`]: ../struct.Context.html#method.set_subscribe_callback
     //! [`subscription_masks`]: subscription_masks/index.html
     
    +use std;
     use capi;
     use std::os::raw::c_void;
     use super::{ContextInternal, Context};
    @@ -211,8 +212,10 @@ impl Context {
     /// must be accomplished separately to avoid a memory leak.
     extern "C"
     fn cb_proxy(_: *mut ContextInternal, et: EventType, index: u32, userdata: *mut c_void) {
    -    let facility = get_facility(et);
    -    let operation = get_operation(et);
    -    let callback = Callback::get_callback(userdata);
    -    callback(facility, operation, index);
    +    let _ = std::panic::catch_unwind(|| {
    +        let facility = get_facility(et);
    +        let operation = get_operation(et);
    +        let callback = Callback::get_callback(userdata);
    +        (callback)(facility, operation, index);
    +    });
     }
    
  • pulse-binding/src/mainloop/api.rs+5 3 modified
    @@ -378,7 +378,9 @@ impl<'a> From<&'a MainloopApi> for *const ApiInternal {
     /// Warning: This is for single-use cases only! It destroys the actual closure callback.
     extern "C"
     fn once_cb_proxy(_: *const ApiInternal, userdata: *mut c_void) {
    -    // Note, destroys closure callback after use - restoring outer box means it gets dropped
    -    let mut callback = ::callbacks::get_su_callback::<dyn FnMut()>(userdata);
    -    callback();
    +    let _ = std::panic::catch_unwind(|| {
    +        // Note, destroys closure callback after use - restoring outer box means it gets dropped
    +        let mut callback = ::callbacks::get_su_callback::<dyn FnMut()>(userdata);
    +        (callback)();
    +    });
     }
    
  • pulse-binding/src/mainloop/events/deferred.rs+5 2 modified
    @@ -15,6 +15,7 @@
     
     //! Main loop deferred events.
     
    +use std;
     use std::os::raw::c_void;
     use std::rc::Rc;
     use super::super::api::{MainloopApi, MainloopInnerType};
    @@ -104,6 +105,8 @@ impl<T> Drop for DeferEvent<T>
     pub(crate)
     extern "C"
     fn event_cb_proxy(_: *const MainloopApi, e: *mut DeferEventInternal, userdata: *mut c_void) {
    -    let callback = EventCb::get_callback(userdata);
    -    callback(e);
    +    let _ = std::panic::catch_unwind(|| {
    +        let callback = EventCb::get_callback(userdata);
    +        (callback)(e);
    +    });
     }
    
  • pulse-binding/src/mainloop/events/io.rs+5 2 modified
    @@ -15,6 +15,7 @@
     
     //! Main loop IO events.
     
    +use std;
     use capi;
     use std::os::raw::c_void;
     use std::rc::Rc;
    @@ -116,6 +117,8 @@ extern "C"
     fn event_cb_proxy(_: *const MainloopApi, e: *mut IoEventInternal, fd: i32, events: IoEventFlagSet,
         userdata: *mut c_void)
     {
    -    let callback = EventCb::get_callback(userdata);
    -    callback(e, fd, events);
    +    let _ = std::panic::catch_unwind(|| {
    +        let callback = EventCb::get_callback(userdata);
    +        (callback)(e, fd, events);
    +    });
     }
    
  • pulse-binding/src/mainloop/events/timer.rs+5 2 modified
    @@ -24,6 +24,7 @@
     //! Note that time events created with one form of time value can be freely restarted with the other
     //! form of time value.
     
    +use std;
     use std::os::raw::c_void;
     use std::rc::Rc;
     use libc::timeval;
    @@ -130,6 +131,8 @@ extern "C"
     fn event_cb_proxy(_: *const MainloopApi, e: *mut TimeEventInternal, _: *const timeval,
         userdata: *mut c_void)
     {
    -    let callback = EventCb::get_callback(userdata);
    -    callback(e);
    +    let _ = std::panic::catch_unwind(|| {
    +        let callback = EventCb::get_callback(userdata);
    +        (callback)(e);
    +    });
     }
    
  • pulse-binding/src/mainloop/signal.rs+5 2 modified
    @@ -23,6 +23,7 @@
     //! support for UNIX signals. However, you may hook signal support into an abstract main loop via
     //! the routines defined herein.
     
    +use std;
     use capi;
     use std::os::raw::c_void;
     use std::ptr::null_mut;
    @@ -89,6 +90,8 @@ extern "C"
     fn signal_cb_proxy(_api: *const ApiInternal, _e: *mut EventInternal, sig: i32,
         userdata: *mut c_void)
     {
    -    let callback = SignalCb::get_callback(userdata);
    -    callback(sig);
    +    let _ = std::panic::catch_unwind(|| {
    +        let callback = SignalCb::get_callback(userdata);
    +        (callback)(sig);
    +    });
     }
    
  • pulse-binding/src/operation.rs+5 2 modified
    @@ -15,6 +15,7 @@
     
     //! Asynchronous operations.
     
    +use std;
     use capi;
     use std::os::raw::c_void;
     use std::ptr::null_mut;
    @@ -115,6 +116,8 @@ impl<ClosureProto: ?Sized> Drop for Operation<ClosureProto> {
     /// must be accomplished separately to avoid a memory leak.
     extern "C"
     fn notify_cb_proxy(_: *mut OperationInternal, userdata: *mut c_void) {
    -    let callback = NotifyCb::get_callback(userdata);
    -    callback();
    +    let _ = std::panic::catch_unwind(|| {
    +        let callback = NotifyCb::get_callback(userdata);
    +        (callback)();
    +    });
     }
    
  • pulse-binding/src/stream.rs+24 16 modified
    @@ -1663,28 +1663,34 @@ impl Drop for Stream {
     /// Warning: This is for single-use cases only! It destroys the actual closure callback.
     extern "C"
     fn success_cb_proxy(_: *mut StreamInternal, success: i32, userdata: *mut c_void) {
    -    // Note, destroys closure callback after use - restoring outer box means it gets dropped
    -    let mut callback = ::callbacks::get_su_callback::<dyn FnMut(bool)>(userdata);
         let success_actual = match success { 0 => false, _ => true };
    -    callback(success_actual);
    +    let _ = std::panic::catch_unwind(|| {
    +        // Note, destroys closure callback after use - restoring outer box means it gets dropped
    +        let mut callback = ::callbacks::get_su_callback::<dyn FnMut(bool)>(userdata);
    +        (callback)(success_actual);
    +    });
     }
     
     /// Proxy for request callbacks.
     /// Warning: This is for multi-use cases! It does **not** destroy the actual closure callback, which
     /// must be accomplished separately to avoid a memory leak.
     extern "C"
     fn request_cb_proxy(_: *mut StreamInternal, nbytes: usize, userdata: *mut c_void) {
    -    let callback = RequestCb::get_callback(userdata);
    -    callback(nbytes);
    +    let _ = std::panic::catch_unwind(|| {
    +        let callback = RequestCb::get_callback(userdata);
    +        (callback)(nbytes);
    +    });
     }
     
     /// Proxy for notify callbacks.
     /// Warning: This is for multi-use cases! It does **not** destroy the actual closure callback, which
     /// must be accomplished separately to avoid a memory leak.
     extern "C"
     fn notify_cb_proxy(_: *mut StreamInternal, userdata: *mut c_void) {
    -    let callback = NotifyCb::get_callback(userdata);
    -    callback();
    +    let _ = std::panic::catch_unwind(|| {
    +        let callback = NotifyCb::get_callback(userdata);
    +        (callback)();
    +    });
     }
     
     /// Proxy for event callbacks.
    @@ -1694,13 +1700,15 @@ extern "C"
     fn event_cb_proxy(_: *mut StreamInternal, name: *const c_char,
         proplist: *mut ::proplist::ProplistInternal, userdata: *mut c_void)
     {
    -    assert!(!name.is_null());
    -    let n = {
    -        let tmp = unsafe { CStr::from_ptr(name) };
    -        tmp.to_string_lossy().into_owned()
    -    };
    -    let pl = Proplist::from_raw_weak(proplist);
    -
    -    let callback = EventCb::get_callback(userdata);
    -    callback(n, pl);
    +    let _ = std::panic::catch_unwind(|| {
    +        assert!(!name.is_null());
    +        let n = {
    +            let tmp = unsafe { CStr::from_ptr(name) };
    +            tmp.to_string_lossy().into_owned()
    +        };
    +        let pl = Proplist::from_raw_weak(proplist);
    +
    +        let callback = EventCb::get_callback(userdata);
    +        (callback)(n, pl);
    +    });
     }
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.