binaryninja-api icon indicating copy to clipboard operation
binaryninja-api copied to clipboard

Rust wrapper `Activity::new_with_action` is broken

Open comex opened this issue 4 months ago • 0 comments

Version and Platform (required):

  • Binary Ninja Version: binaryninja-api dev/5.2.8353
  • Edition: Commercial
  • OS: macOS
  • OS Version: 26.0.1 (25A362)
  • CPU Architecture: arm64

Bug Description: From rust/src/workflow/activity.rs:

    pub fn new_with_action<F>(config: impl AsConfig, mut action: F) -> Ref<Self>
    where
        F: FnMut(&AnalysisContext),
    {
        unsafe extern "C" fn cb_action<F: FnMut(&AnalysisContext)>(
            ctxt: *mut c_void,
            analysis: *mut BNAnalysisContext,
        ) {
            let ctxt = &mut *(ctxt as *mut F);
            if let Some(analysis) = NonNull::new(analysis) {
                ctxt(&AnalysisContext::from_raw(analysis))
            }
        }
        let config = config.as_config();
        let result = unsafe {
            BNCreateActivity(
                config.as_ptr(),
                &mut action as *mut F as *mut c_void,
                Some(cb_action::<F>),
            )
        };
        unsafe { Activity::ref_from_raw(NonNull::new(result).unwrap()) }
    }

This follows a standard pattern for wrapping C APIs that use callbacks, using a wrapper function in order to allow new_with_action to be called with any object implementing FnMut(&AnalysisContext).

Except, the object is supposed to be stored somewhere. :) In this case, the code just passes &mut action, which is a pointer to action on the stack. This is not valid since the callback will be called after new_with_action has already returned.

This will appear to work if you pass a callback that is a plain function or a closure with no captures, since in that case the contents of the object aren't used. But it will break as soon as you pass a closure with captures.

comex avatar Oct 09 '25 03:10 comex