# Casting c\_void\* for C-Callback

**URL:** <https://users.rust-lang.org/t/casting-c-void-for-c-callback/24293>\
**Category:** help\
**Created:** [January 17, 2019, 3:29pm UTC](https://users.rust-lang.org/t/casting-c-void-for-c-callback/24293 "2019-01-17T15:29:18Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![wspeirs](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/wspeirs/32/6394_2.png) [@wspeirs](https://users.rust-lang.org/u/wspeirs)\
**Post date:** [January 17, 2019, 3:29pm UTC](https://users.rust-lang.org/t/casting-c-void-for-c-callback/24293/1 "2019-01-17T15:29:18Z")

</div>

I'm working on a wrapper around `libhackrf`: [GitHub - wspeirs/rs-libhackrf: libhackrf as a Rust crate](https://github.com/wspeirs/rs-libhackrf)

I'm having a problem packaging up a context (generic) and function (callback), casting it as a c\_void pointer, and then casting it back on the other side. The problem I have is that Valgrind indicates an uninitialized read.

The following code snipit will make more sense:

```rust
#[repr(C)]
struct CallbackContext<'a, T> {
    context: Option<&'a mut T>,
    function: &'a mut FnMut(&[u8], &Option<&mut T>) -> Error
}

impl <'a> Device<'a> {
    unsafe extern "C" fn rx_callback<C>(transfer: *mut hackrf_transfer) -> i32
    where C: std::fmt::Debug {
        let buffer :&[u8] = slice::from_raw_parts((*transfer).buffer, (*transfer).valid_length as usize);

        let ctx = (*(*transfer).device).rx_ctx;
        let ctx = &mut *(ctx as *mut Box<CallbackContext<C>>);

        Into::into((ctx.function)(buffer, &ctx.context)) // line 88
    }

    pub fn start_rx<T, F>(&mut self, mut callback: F, rx_ctx: Option<&mut T>) -> Result<(), Error>
    where F: FnMut(&[u8], &Option<&mut T>) -> Error,
    T: std::fmt::Debug {
        unsafe {
            // package up our context and function
            let mut ctx = Box::new(CallbackContext {
                context: rx_ctx,
                function: &mut callback
            });

            // calling leak so when Box is dropped, the memory 
            let ctx = Box::leak(ctx) as *mut _ as *mut c_void;isn't freed

            // this function creates a thread (pthread) and runs it
            let ret = hackrf_start_rx(self.device_ptr, Some(Device::rx_callback::<T>), ctx);

            if ret != hackrf_error_HACKRF_SUCCESS {
                return Err(Error::from(ret));
            }
        }

        // set the state so we can cleanup properly
        self.state = State::RECEIVING;

        Ok( () )
    }
}

```

I'm calling `start_rx` as follows:

```rust
    #[test]
    fn start_stop_rx() {
        LOGGER_INIT.call_once(|| simple_logger::init_with_level(log::Level::Trace).unwrap());

        let mut hrf = HackRF::new().expect("Error creating HackRF");
        let mut dev = hrf.open_device(0).expect("Error creating device; maybe not plugged in?");

        let ctx = None::<&mut i32>;

        dev.start_rx(|b, c| {
            Error::SUCCESS
        }, ctx).expect("Error calling start_rx");

        thread::sleep_ms(250);

        dev.stop_rx().expect("Error calling stop_rx");
    }

```

... and the error in Valgrind:

```rust
==32509== Thread 4:
==32509== Invalid read of size 8
==32509== at 0x135E35: rs_libhackrf::device::Device::rx_callback::haf9645800687a434 (device.rs:88)
==32509== by 0x4E3E21C: hackrf_libusb_transfer_callback (in /usr/local/lib/libhackrf.so.0.5.0)
==32509== by 0x5F5D159: ??? (in /lib/x86_64-linux-gnu/libusb-1.0.so.0.1.0)
==32509== by 0x5F62F07: ??? (in /lib/x86_64-linux-gnu/libusb-1.0.so.0.1.0)
==32509== by 0x5F5CC48: ??? (in /lib/x86_64-linux-gnu/libusb-1.0.so.0.1.0)
==32509== by 0x5F5DB52: libusb_handle_events_timeout_completed (in /lib/x86_64-linux-gnu/libusb-1.0.so.0.1.0)
==32509== by 0x4E3E14A: transfer_threadproc (in /usr/local/lib/libhackrf.so.0.5.0)
==32509== by 0x54556B9: start_thread (pthread_create.c:333)
==32509== by 0x598841C: clone (clone.S:109)
==32509== Address 0x8 is not stack'd, malloc'd or (recently) free'd
==32509== 
==32509== 
==32509== Process terminating with default action of signal 11 (SIGSEGV)
==32509== Access not within mapped region at address 0x40008
==32509== at 0x135E35: rs_libhackrf::device::Device::rx_callback::haf9645800687a434 (device.rs:88)
==32509== by 0x4E3E21C: hackrf_libusb_transfer_callback (in /usr/local/lib/libhackrf.so.0.5.0)
==32509== by 0x5F5D159: ??? (in /lib/x86_64-linux-gnu/libusb-1.0.so.0.1.0)
==32509== by 0x5F62F07: ??? (in /lib/x86_64-linux-gnu/libusb-1.0.so.0.1.0)
==32509== by 0x5F5CC48: ??? (in /lib/x86_64-linux-gnu/libusb-1.0.so.0.1.0)
==32509== by 0x5F5DB52: libusb_handle_events_timeout_completed (in /lib/x86_64-linux-gnu/libusb-1.0.so.0.1.0)
==32509== by 0x4E3E14A: transfer_threadproc (in /usr/local/lib/libhackrf.so.0.5.0)
==32509== by 0x54556B9: start_thread (pthread_create.c:333)
==32509== by 0x598841C: clone (clone.S:109)
==32509== If you believe this happened as a result of a stack
==32509== overflow in your program's main thread (unlikely but
==32509== possible), you can try to increase the size of the
==32509== main thread stack using the --main-stacksize= flag.
==32509== The main thread stack size used in this run was 8388608.
==32509== 
==32509== HEAP SUMMARY:
==32509== in use at exit: 0 bytes in 0 blocks
==32509== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==32509== 
==32509== All heap blocks were freed -- no leaks are possible
==32509== 
==32509== For counts of detected and suppressed errors, rerun with: -v
==32509== ERROR SUMMARY: 2 errors from 1 contexts (suppressed: 0 from 0)
Killed

```

I have gotten this to "work" as it runs to completion, but I _aways_ get the invalid/uninitialized read error on line 88 when I go to use the context. When it does work, any attempt to access `ctx.context` causes the error.

How should I go about doing this? I _think_ I need to put my `CallbackContext` on the heap so that it survives the call to `hackrf_start_rx`. However, I'm not 100% sure how to clean it up after. Thoughts? Thanks!

---

<div class="post-metadata">

**Author:** ![Riateche](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/riateche/32/3002_2.png) [@Riateche](https://users.rust-lang.org/u/Riateche)\
**Post date:** [January 17, 2019, 5:11pm UTC](https://users.rust-lang.org/t/casting-c-void-for-c-callback/24293/2 "2019-01-17T17:11:14Z")

</div>

Not sure what's causing the problem, but why do you need `context: Option<&'a mut T>`? A lambda by itself can capture any context it needs, so there is no need to pass variables explicitly.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/kornel/32/4823_2.png) [@kornel](https://users.rust-lang.org/u/kornel)\
**Post date:** [January 17, 2019, 5:27pm UTC](https://users.rust-lang.org/t/casting-c-void-for-c-callback/24293/3 "2019-01-17T17:27:16Z")

</div>

1. Instead of `Box::leak` it's better to use:

2. Your code either doesn't need to use `Box`, or has a use-after-free bug. `Box<struct with &mut>` doesn't make sense, because even though the Box is long-lived, the `&mut` reference is only temporary. You can't make `&mut` non-temporary.

If the FFI code could possibly use the callback after `start_rx` returns, then you can't use any `&` or `&mut` anywhere in the data that FFI can see. You must copy or own everything, e.g. `Box<dyn FnMut…`.

If the FFI code certainly won't use the callback after `hackrf_start_rx`, then you don't need `Box` at all. You can pass reference to a local variable.

---

<div class="post-metadata">

**Author:** ![wspeirs](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/wspeirs/32/6394_2.png) [@wspeirs](https://users.rust-lang.org/u/wspeirs)\
**Post date:** [January 18, 2019, 12:22am UTC](https://users.rust-lang.org/t/casting-c-void-for-c-callback/24293/4 "2019-01-18T00:22:03Z")

</div>

@Riateche I wasn't sure about the function capturing context. I wasn't sure how the compiler would know how to deal with captured context being cast to a `c_void` pointer, and back again. Thought it better to explicitly pass some context... but I'll give this approach a shot, as it's cleaner.

@kornel taking your advice as well, from point #2, I'm left with the following code that doesn't compile now:

```rust
    unsafe extern "C" fn rx_callback(transfer: *mut hackrf_transfer) -> i32 {
        // construct a slice given the pointer and valid length
        let buffer :&[u8] = slice::from_raw_parts((*transfer).buffer, (*transfer).valid_length as usize);

        // construct the context, "casting" back to a CallbackContext
        let ctx = (*transfer).rx_ctx;

        let callback= &mut *(ctx as *mut FnMut(&[u8]) -> Error);

        // call the function, and convert the Error into an i32
        Into::into(callback(buffer))
    }

    pub fn start_rx(&mut self, callback: &mut FnMut(&[u8]) -> Error) -> Result<(), Error> {
        unsafe {
            let ctx = (callback as *mut FnMut(&[u8]) -> Error) as *mut c_void;

            // call the underlying function
            let ret = hackrf_start_rx(self.device_ptr, Some(Device::rx_callback), ctx);

            if ret != hackrf_error_HACKRF_SUCCESS {
                return Err(Error::from(ret));
            }
        }

        // set the state so we can cleanup properly
        self.state = State::RECEIVING;

        Ok( () )
    }

```

I get the following compiler error:

```rust
error[E0277]: expected a `std::ops::FnMut<(&[u8],)>` closure, found `std::ffi::c_void`
  --> src/device.rs:80:30
   |
80 | let callback= &mut *(ctx as *mut FnMut(&[u8]) -> Error);
   | ^^^ expected an `FnMut<(&[u8],)>` closure, found `std::ffi::c_void`
   |
   = help: the trait `for<'r> std::ops::FnMut<(&'r [u8],)>` is not implemented for `std::ffi::c_void`
   = note: required for the cast to the object type `dyn for<'r> std::ops::FnMut(&'r [u8]) -> error::Error`

```

This is confusing because I would have _thought_ that I could have cast a `c_void` (which ctx is) to any `*mut` I wanted... but for some reason this isn't working. Thoughts? Thanks!

---

<div class="post-metadata">

**Author:** ![kornel](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/kornel/32/4823_2.png) [@kornel](https://users.rust-lang.org/u/kornel)\
**Post date:** [January 18, 2019, 12:25am UTC](https://users.rust-lang.org/t/casting-c-void-for-c-callback/24293/5 "2019-01-18T00:25:38Z")

</div>

References to closures aren't pointers. They are structs that contain function pointer and a context pointer.

However you can take address of the reference (reference of reference of closure) and cast that to a pointer.

---

<div class="post-metadata">

**Author:** ![wspeirs](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/wspeirs/32/6394_2.png) [@wspeirs](https://users.rust-lang.org/u/wspeirs)\
**Post date:** [January 18, 2019, 2:28am UTC](https://users.rust-lang.org/t/casting-c-void-for-c-callback/24293/6 "2019-01-18T02:28:56Z")

</div>

@kornel, the problem I'm having is not going from closure to `*mut c_void`, the problem I'm having is going from `*mut c_void` to closure:

```rust
80 | let callback= &mut *(ctx as *mut FnMut(&[u8]) -> Error);
   | ^^^ expected an `FnMut<(&[u8],)>` closure, found `std::ffi::c_void`
   |
   = help: the trait `for<'r> std::ops::FnMut<(&'r [u8],)>` is not implemented for `std::ffi::c_void`
   = note: required for the cast to the object type `dyn for<'r> std::ops::FnMut(&'r [u8]) -> error::Error`

```

In the above, `ctx` is a `*mut c_void`: `let ctx :*mut c_void = (*transfer).rx_ctx;`.

---

<div class="post-metadata">

**Author:** ![wspeirs](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/wspeirs/32/6394_2.png) [@wspeirs](https://users.rust-lang.org/u/wspeirs)\
**Post date:** [January 18, 2019, 3:30am UTC](https://users.rust-lang.org/t/casting-c-void-for-c-callback/24293/7 "2019-01-18T03:30:22Z")

</div>

Taking another stab at this, going off this [SO post](https://stackoverflow.com/questions/38995701/how-do-i-pass-closures-through-raw-pointers-as-arguments-to-c-functions), I'm left with:

```rust
    unsafe extern "C" fn rx_callback(transfer: *mut hackrf_transfer) -> i32 {
        let buffer :&[u8] = slice::from_raw_parts((*transfer).buffer, (*transfer).valid_length as usize);

        let ctx :*mut c_void = (*transfer).rx_ctx;
        let callback :&mut &mut FnMut(&[u8]) -> Error = transmute(ctx);

        Into::into(callback(buffer.as_slice())) // <- device.rs:91, see Valgrind error
    }

    pub fn start_rx<F>(&mut self, mut callback: F) -> Result<(), Error>
    where F: FnMut(&[u8]) -> Error {
        unsafe {
            let mut trait_obj: &mut FnMut(&[u8]) -> Error = &mut callback;
            let ctx :*mut c_void = transmute(&mut trait_obj);

            let ret = hackrf_start_rx(self.device_ptr, Some(Device::rx_callback), ctx);
        }

        Ok( () )
    }

```

However, I'm still getting a crash and Valgrind is reporting uninit reads:

```rust
==9809== Thread 4:
==9809== Use of uninitialised value of size 8
==9809== at 0x175B9C: core::ops::function::impls::_$LT$impl$u20$core..ops..function..FnMut$LT$A$GT$$u20$for$u20$$RF$mut$u20$F$GT$::call_mut::h56ab5d92929ca72f (function.rs:276)
==9809== by 0x13634E: rs_libhackrf::device::Device::rx_callback::ha10f0099c22d419d (device.rs:91)
==9809== by 0x4E3E21C: hackrf_libusb_transfer_callback (in /usr/local/lib/libhackrf.so.0.5.0)
==9809== by 0x5F5D159: ??? (in /lib/x86_64-linux-gnu/libusb-1.0.so.0.1.0)
==9809== by 0x5F62F07: ??? (in /lib/x86_64-linux-gnu/libusb-1.0.so.0.1.0)
==9809== by 0x5F5CC48: ??? (in /lib/x86_64-linux-gnu/libusb-1.0.so.0.1.0)
==9809== by 0x5F5DB52: libusb_handle_events_timeout_completed (in /lib/x86_64-linux-gnu/libusb-1.0.so.0.1.0)
==9809== by 0x4E3E14A: transfer_threadproc (in /usr/local/lib/libhackrf.so.0.5.0)
==9809== by 0x54556B9: start_thread (pthread_create.c:333)
==9809== by 0x598841C: clone (clone.S:109)
==9809== Uninitialised value was created by a stack allocation
==9809== at 0x545EC12: ??? (syscall-template.S:84)

```

It complains the value was created on the stack, which makes sense because `trait_obj` lives on the stack. I tried to get around this by simply doing: `let ctx :*mut c_void = transmute(&mut &mut callback);` but I get into the same situation, an uninit read from a value created via stack allocation.

I'm starting to wonder if this is possible at all: create a `*mut c_void` that points at a closure, and is passed through a C `void *` where it can be re-cast back to the original closure. Thoughts? Thanks!

---

<div class="post-metadata">

**Author:** ![vitalyd](https://avatars.discourse-cdn.com/v4/letter/v/edb3f5/32.png) [@vitalyd](https://users.rust-lang.org/u/vitalyd)\
**Post date:** [January 18, 2019, 3:55am UTC](https://users.rust-lang.org/t/casting-c-void-for-c-callback/24293/8 "2019-01-18T03:55:55Z")

</div>

The `callback` in start\_rx is dropped at the end of that function, and hence doesn’t live long enough for your rx thread to call it back properly.

If you don’t have an existing stack or heap location to hold a stable address for your callback, you need to allocate it on the heap (eg get a `Box<Box<dyn FnMut(&[u8]) -> Error>>`), then `Box::into_raw` that so it doesn’t get dropped, store the resulting `*mut *mut ...` in the context, restore back to that Box (via Box::from\_raw) in the rx callback, invoke the closure, and let the box drop to deallocate.

I’m on mobile so a bit terse above - sorry.

---

<div class="post-metadata">

**Author:** ![wspeirs](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/wspeirs/32/6394_2.png) [@wspeirs](https://users.rust-lang.org/u/wspeirs)\
**Post date:** [January 18, 2019, 12:25pm UTC](https://users.rust-lang.org/t/casting-c-void-for-c-callback/24293/9 "2019-01-18T12:25:59Z")

</div>

@vitalyd, thanks for the help! Makes sense that the `callback` parameter to `start_rx` is dropped at the end of the call to `start_rx`. I changed it so that the boxing happens outside this function, but I'm still missing something:

```rust
     unsafe extern "C" fn rx_callback(transfer: *mut hackrf_transfer) -> i32 {
        let buffer :&[u8] = slice::from_raw_parts((*transfer).buffer, (*transfer).valid_length as usize);

        let ctx :*mut c_void = (*transfer).rx_ctx;
        let callback :*mut Box<FnMut(&[u8]) -> Error> = transmute(ctx);
        let mut callback = Box::from_raw(callback);

        Into::into((*(*callback))(buffer.as_slice())) // <- device.rs:92, see Valgrind output
    }

    pub fn start_rx<F>(&mut self, callback: Box<Box<F>>) -> Result<(), Error>
    where F: FnMut(&[u8]) -> Error {
        unsafe {
            let ctx :*mut c_void = transmute(Box::into_raw(callback));

            let ret = hackrf_start_rx(self.device_ptr, Some(Device::rx_callback), ctx);

            if ret != hackrf_error_HACKRF_SUCCESS {
                return Err(Error::from(ret));
            }
        }
        Ok( () )
    }

```

I simply call `into_raw` on `callback` which _should_ create a temporary, but that temp only holds the location of the outer `Box` pointer. (Not 100% sure why I need the double-Box, but going with it.) This temporary is then "cast" into a `*mut c_void` and passed as a parameter... which all makes sense.

On the unpacking side, I'm converting from `*mut c_void` into `*mut Box<F>`, which I then construct into a `Box` via `Box::from_raw`, which _should_ leave me with my original `Box<Box<F>>`. I double-deref so I can get the function `F` and call it. The result, a crash:

```rust
==32213== Thread 4:
==32213== Invalid read of size 8
==32213== at 0x136417: rs_libhackrf::device::Device::rx_callback::ha10f0099c22d419d (device.rs:92)
==32213== by 0x4E3E21C: hackrf_libusb_transfer_callback (in /usr/local/lib/libhackrf.so.0.5.0)
==32213== by 0x5F5D159: ??? (in /lib/x86_64-linux-gnu/libusb-1.0.so.0.1.0)
==32213== by 0x5F62F07: ??? (in /lib/x86_64-linux-gnu/libusb-1.0.so.0.1.0)
==32213== by 0x5F5CC48: ??? (in /lib/x86_64-linux-gnu/libusb-1.0.so.0.1.0)
==32213== by 0x5F5DB52: libusb_handle_events_timeout_completed (in /lib/x86_64-linux-gnu/libusb-1.0.so.0.1.0)
==32213== by 0x4E3E14A: transfer_threadproc (in /usr/local/lib/libhackrf.so.0.5.0)
==32213== by 0x54556B9: start_thread (pthread_create.c:333)
==32213== by 0x598841C: clone (clone.S:109)
==32213== Address 0x4d0000352d4c is not stack'd, malloc'd or (recently) free'd
==32213== 
==32213== 
==32213== Process terminating with default action of signal 11 (SIGSEGV)
==32213== Access not within mapped region at address 0x18
==32213== at 0x136417: rs_libhackrf::device::Device::rx_callback::ha10f0099c22d419d (device.rs:92)
==32213== by 0x4E3E21C: hackrf_libusb_transfer_callback (in /usr/local/lib/libhackrf.so.0.5.0)
==32213== by 0x5F5D159: ??? (in /lib/x86_64-linux-gnu/libusb-1.0.so.0.1.0)
==32213== by 0x5F62F07: ??? (in /lib/x86_64-linux-gnu/libusb-1.0.so.0.1.0)
==32213== by 0x5F5CC48: ??? (in /lib/x86_64-linux-gnu/libusb-1.0.so.0.1.0)
==32213== by 0x5F5DB52: libusb_handle_events_timeout_completed (in /lib/x86_64-linux-gnu/libusb-1.0.so.0.1.0)
==32213== by 0x4E3E14A: transfer_threadproc (in /usr/local/lib/libhackrf.so.0.5.0)
==32213== by 0x54556B9: start_thread (pthread_create.c:333)
==32213== by 0x598841C: clone (clone.S:109)

```

So clearly I'm de-referencing something improperly. Thoughts on all of this? Is my logic of passing `Box<Box<F>>` into my function sound? Ergonomically not great, but at this point I'm simply looking for _something_ that'll run without crashing or an uninitialized read. Thoughts? Thanks!

---

<div class="post-metadata">

**Author:** ![vitalyd](https://avatars.discourse-cdn.com/v4/letter/v/edb3f5/32.png) [@vitalyd](https://users.rust-lang.org/u/vitalyd)\
**Post date:** [January 18, 2019, 1:57pm UTC](https://users.rust-lang.org/t/casting-c-void-for-c-callback/24293/10 "2019-01-18T13:57:45Z")

</div>

The problem here is you have `Box<Box<F>>`, with a concrete `F: FnMut`, which isn't a trait object, but you're casting it back to a trait object in `rx_callback`, and calling it as-if it's a trait object.

You need to have a `Box<Box<dyn FnMut(&[u8])>>` on both sides. [Here](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d739286c6ac69d2726c07afbb044d5ec) is a contrived example to hopefully help you.

---

<div class="post-metadata">

**Author:** ![wspeirs](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/wspeirs/32/6394_2.png) [@wspeirs](https://users.rust-lang.org/u/wspeirs)\
**Post date:** [January 19, 2019, 3:49am UTC](https://users.rust-lang.org/t/casting-c-void-for-c-callback/24293/11 "2019-01-19T03:49:45Z")

</div>

@vitalyd, thanks again for the help! I took your example, and modified it to more closely fit what I'm trying to do, but still running into an issue, that I honestly don't think there is a great solution to. When I'm in my call-back `rx_callback` I'm converting the `*mut c_void` into a `Box` using `Box::from_raw`; however, when the function returns and this is dropped, the memory is freed, but I still need this pointer to be there the next time `rx_callback` is called from the thread! A simplified version of my code:

```rust
    unsafe extern "C" fn rx_callback(transfer: *mut hackrf_transfer) -> i32 {
        // get the callback context out of the transfer struct
        let callback :*mut c_void = (*transfer).rx_ctx;
        let mut callback :Box<Box<dyn FnMut(&[u8]) -> Error>> = Box::from_raw(callback as _);
        let callback = callback.as_mut().as_mut();

        // call the function
        Into::into(callback(buffer)) // the problem is that buffer is dropped here, freeing the memory!!!
    }

    pub fn start_rx<F>(&mut self, callback: F) -> Result<(), Error>
    where F: FnMut(&[u8]) -> Error
    {
        unsafe {
            let ctx :Box<dyn FnMut(&[u8]) -> Error> = Box::new(callback);
            let ctx = Box::new(ctx);
            let ctx :*mut c_void = Box::into_raw(ctx) as _;

            // this function starts a pthread that calls rx_callback multiple times
            let ret = hackrf_start_rx(self.device_ptr, Some(Device::rx_callback), ctx);

            if ret != hackrf_error_HACKRF_SUCCESS {
                return Err(Error::from(ret));
            }
        }

        Ok( () )
    }

```

The above causes a seg fault in jemalloc... I believe because of multiple frees.

One thought I had was instead of using `Box::from_raw` I need to cast the pointer somehow, then when I _know_ there are no more calls to `rx_callback` I can capture the pointer, and call `Box::from_raw`, and then drop it. Thoughts? Thanks!

---

<div class="post-metadata">

**Author:** ![wspeirs](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/wspeirs/32/6394_2.png) [@wspeirs](https://users.rust-lang.org/u/wspeirs)\
**Post date:** [January 19, 2019, 4:17am UTC](https://users.rust-lang.org/t/casting-c-void-for-c-callback/24293/12 "2019-01-19T04:17:07Z")

</div>

Yea, so if I use `Box::leak` I can get it to work without any errors, but of course I'm leaking memory...

```rust
        let callback :*mut c_void = (*transfer).rx_ctx;
        let mut callback :Box<Box<dyn FnMut(&[u8]) -> Error>> = Box::from_raw(callback as _);
        let callback = Box::leak(callback);
        let callback = callback.as_mut();

        // call the function, and convert the Error into an i32
        Into::into(callback(buffer))

```

... but from Valgrind:

```rust
==12320== HEAP SUMMARY:
==12320== in use at exit: 56 bytes in 3 blocks
==12320== total heap usage: 4,121 allocs, 4,118 frees, 3,116,559 bytes allocated
==12320== 
==12320== LEAK SUMMARY:
==12320== definitely lost: 16 bytes in 1 blocks
==12320== indirectly lost: 0 bytes in 0 blocks
==12320== possibly lost: 0 bytes in 0 blocks
==12320== still reachable: 40 bytes in 2 blocks

```

Haven't tried capturing the pointer, and freeing it later... that's the next step I guess. I'm just happy to see zero errors in Valgrind 🙂

---

<div class="post-metadata">

**Author:** ![vitalyd](https://avatars.discourse-cdn.com/v4/letter/v/edb3f5/32.png) [@vitalyd](https://users.rust-lang.org/u/vitalyd)\
**Post date:** [January 19, 2019, 4:17am UTC](https://users.rust-lang.org/t/casting-c-void-for-c-callback/24293/13 "2019-01-19T04:17:20Z")

</div>

> [@wspeirs](#):
>
> One thought I had was instead of using `Box::from_raw` I need to cast the pointer somehow, then when I _know_ there are no more calls to `rx_callback` I can capture the pointer, and call `Box::from_raw` , and then drop it. Thoughts?

Ah, yes - I didn’t realize the callback is used more than once, thought it was a one-shot type of deal.

So yeah, don’t create the Box from the `*mut c_void` there, wait till you’re fully done as you said. Cast the raw ptr to `*mut *mut dyn FnMut(...)`, and then coerce that to a borrowed trait obj, ie:

```rust
let callback = (*transfer).rx_ctx as *mut *mut dyn FnMut(&[u8]) -> Error;
let callback = unsafe { &mut **callback };
Into::into(callback(buffer))
```

---

<div class="post-metadata">

**Author:** ![wspeirs](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/wspeirs/32/6394_2.png) [@wspeirs](https://users.rust-lang.org/u/wspeirs)\
**Post date:** [January 19, 2019, 4:19am UTC](https://users.rust-lang.org/t/casting-c-void-for-c-callback/24293/14 "2019-01-19T04:19:10Z")

</div>

@vitalyd, just tried the above, same net effect... no errors, but leaked memory. Capturing the pointer and freeing it later is a task for tomorrow. Thanks again for all the help!!!

---

<div class="post-metadata">

**Author:** ![vitalyd](https://avatars.discourse-cdn.com/v4/letter/v/edb3f5/32.png) [@vitalyd](https://users.rust-lang.org/u/vitalyd)\
**Post date:** [January 19, 2019, 4:20am UTC](https://users.rust-lang.org/t/casting-c-void-for-c-callback/24293/15 "2019-01-19T04:20:58Z")

</div>

> [@wspeirs](#):
>
> just tried the above, same net effect… no errors, but leaked memory. Capturing the pointer and freeing it later is a task for tomorrow. Thanks again for all the help!!!

Yeah, you’ll need to free manually when it’s the right time. Doing the coercion there just saves you the silly Box leak dance.

No problem - good luck!

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/steffahn/32/47569_2.png) [@steffahn](https://users.rust-lang.org/u/steffahn)\
**Post date:** [January 12, 2023, 8:49am UTC](https://users.rust-lang.org/t/casting-c-void-for-c-callback/24293/16 "2023-01-12T08:49:57Z")

</div>

Closed on January 12, 2023, 8:49am UTC


