3

I'm trying to create some bindings from a C library for rust with bindgen and everything was going well until I realized that my program was having memory leak problems

enter image description here

Thanks to heaptrack I was able to identify the function that was causing these memory leaks,

enter image description here

this function CP56Time2a_createFromMsTimestamp creates a timestamp to then be added to another structure (InformationObject) before being sent, when this structure is sent a method is called that frees the memory of the structure (InformationObject_destroy) and I guess also the memory of the timestamp, in the library there is no method to free the memory of the timestamp

How can I deallocate or free this memory? The resulting structure of the function is a pointer *mut sCP56Time2a

minimal example of what I'm doing:

use iec60870::bindings;
use std::ffi::CString;

pub struct CP56Time2a;

impl CP56Time2a {
    pub fn create() -> *mut bindings::sCP56Time2a {
        unsafe {
            bindings::CP56Time2a_createFromMsTimestamp(
                std::ptr::null_mut(),
                bindings::Hal_getTimeInMs(),
            )
        }
    }
}

pub struct Slave {
    inner: bindings::CS104_Slave,
}

impl Slave {
    pub fn new(addr: &str, port: i32) -> Self {
        let inner = unsafe {
            let inner = bindings::CS104_Slave_create(100, 100);
            let address = CString::new(addr).unwrap().as_c_str().to_owned();
            bindings::CS104_Slave_setLocalAddress(inner, address.as_ptr());
            bindings::CS104_Slave_setLocalPort(inner, port);
            bindings::CS104_Slave_setServerMode(inner, 1);

            inner
        };

        Self { inner }
    }
}

fn main() {
    unsafe {
        let slave = Slave::new("127.0.0.1", 2404);
        let param = bindings::CS104_Slave_getAppLayerParameters(slave.inner);

        let asdu = bindings::CS101_ASDU_create(param, false, 3, 0, 1, false, false);
        let timestamp = CP56Time2a::create();

        let me = bindings::MeasuredValueScaledWithCP56Time2a_create(
            std::ptr::null_mut(),
            1000,
            20,
            0,
            timestamp,
        );

        bindings::CS101_ASDU_addInformationObject(asdu, me as bindings::InformationObject);
        // send asdu
        bindings::InformationObject_destroy(me as bindings::InformationObject);
        bindings::CS101_ASDU_destroy(asdu);
    }
}
  • Please specify whether the library you are binding to is a C or C++ library (by removing tags). There are rare cases where it could be both, but in general it's either one or the other. – Matthieu M. Dec 13 '22 at 13:44
  • @MatthieuM. sorry, i already removed the c++ tag – Ivan Raul Sanchez Diaz Dec 13 '22 at 13:46
  • 2
    Glancing at the docs and source of the library, you can pass that function a pointer to a `CP56Time2a` which it will initialize for you (instead of allocating a new one). None of the test or example code passes NULL there. and `MeasuredValueScaledWithCP56Time2a_create` copies the value from the passed timestamp. You can likely just feed it a zeroed value of that type. – Hasturkun Dec 13 '22 at 14:33
  • You're right, but I don't quite understand what to do, according to what I understood from your comment now I'm passing ``std::mem::MaybeUninit::::uninit()`` instead of ``std::ptr::null_mut()`` – Ivan Raul Sanchez Diaz Dec 13 '22 at 15:01
  • I've only done a single test but it seems to have solved the problem :D, is this what you meant? – Ivan Raul Sanchez Diaz Dec 13 '22 at 15:02
  • 1
    Yep, I haven't really delved into Rust much, but I see at least one example in the `bindgen` documentation showing initialization of a struct from a `mem::zeroed` (but `CP56Time2a_createFromMsTimestamp` will zero initialize the value anyway, so uninitialized would be fine, too), plus `bindgen` will apparently create a zeroing `Default` trait for the type (by default) anyway, which will probably be simpler to use. Let Rust deal with the struct's lifetime. – Hasturkun Dec 13 '22 at 15:21
  • thanks you saved my life!, I'm going to read the bindgen documentation and if I find a simpler and more elegant way to solve this I will answer the question – Ivan Raul Sanchez Diaz Dec 13 '22 at 15:32

0 Answers0