Home > Mobile >  Dealloc a pointer(*mut u8)
Dealloc a pointer(*mut u8)

Time:09-28

I have created a ptr using alloc function

let layout = Layout::from_size_align_unchecked(1024 * 8 , align);
println!("Size {}, Align {}", layout.size(), layout.align());
let ptr = alloc(layout);

Now, I have converted this ptr to Vector using from_raw_parts(). After that I am passing this vector using ffi after forgetting at vector using forget(vec). After that I receive ptr, len and capacity from ffi and than I wanted to dealloc that memory.

dealloc(vv.as_mut_ptr(), layout);

Is using delloc method for this use case is right? How can I verify that the memory is actually dellocated? Is there any other way to do this deallocation of memory.

CodePudding user response:

STOP! STOP DOING THIS!

Vectors automatically allocate and deallocate memory, you don’t need these unsafe tricks.

Just use Vec::new or Vec::with_capacity.

let _my_vec = Vec::<u8>::new();

CodePudding user response:

How can I verify that the memory is actually dellocated?

Rust nightly supports LLVM's asan functionality. It is an address sanitizer that checks for those things.

Note that this only works on Unix, Windows is currently not supported.

To activate it, install the nightly toolchain. Then (for address resolution) install llvm:

sudo apt-get install -y llvm

Then all you need to do is run it with:

RUSTFLAGS="-Z sanitizer=address" cargo  nightly run

For example, running the following code gives me:

rustuse std::alloc::{alloc, dealloc, Layout};

fn main() {
    type VecElement = u64;
    let size = 1024;

    let layout = Layout::from_size_align(size * std::mem::size_of::<VecElement>(), 64).unwrap();

    let mut my_vec = unsafe {
        let layout = Layout::from_size_align_unchecked(layout.size(), layout.align());
        println!("Size {}, Align {}", layout.size(), layout.align());
        let ptr = alloc(layout) as *mut VecElement;
        Vec::<VecElement>::from_raw_parts(ptr, 0, size)
    };

    my_vec.push(10);
    println!("{:?}", my_vec);

    unsafe {
        let ptr = my_vec.leak().as_mut_ptr() as *mut u8;
        // dealloc(ptr, layout)
    }
}
Size 8192, Align 64
[10]

=================================================================
==9815==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 8192 byte(s) in 1 object(s) allocated from:
    #0 0x5639279f54c7 in posix_memalign /rustc/llvm/src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:145:3
    #1 0x563927a42329 in std::sys::unix::alloc::aligned_malloc::ha31ca2931b3311a0 /rustc/40336865fe7d4a01139a3336639c6971647e885c/library/std/src/sys/unix/alloc.rs:97:23
    #2 0x563927a42329 in std::sys::unix::alloc::_$LT$impl$u20$core..alloc..global..GlobalAlloc$u20$for$u20$std..alloc..System$GT$::alloc::h8c999cb61b93cc7a /rustc/40336865fe7d4a01139a3336639c6971647e885c/library/std/src/sys/unix/alloc.rs:22:13
    #3 0x563927a42329 in __rdl_alloc /rustc/40336865fe7d4a01139a3336639c6971647e885c/library/std/src/alloc.rs:378:13
    #4 0x563927a1fe77 in rust_tmp::main::h6751a6125ac6d734 /home/martin/work/rust-tmp/src/main.rs:12:19
    #5 0x563927a283ca in core::ops::function::FnOnce::call_once::h3f2ab14fa827b4ba /rustc/40336865fe7d4a01139a3336639c6971647e885c/library/core/src/ops/function.rs:248:5
    #6 0x563927a1f764 in std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd3473a8235573380 /rustc/40336865fe7d4a01139a3336639c6971647e885c/library/std/src/rt.rs:145:18
    #7 0x563927a3cd9e in core::ops::function::impls::_$LT$impl$u20$core..ops..function..FnOnce$LT$A$GT$$u20$for$u20$$RF$F$GT$::call_once::hcd03e0aeba5cfb12 /rustc/40336865fe7d4a01139a3336639c6971647e885c/library/core/src/ops/function.rs:280:13
    #8 0x563927a3cd9e in std::panicking::try::do_call::h2dbc2d91fe9b324b /rustc/40336865fe7d4a01139a3336639c6971647e885c/library/std/src/panicking.rs:492:40
    #9 0x563927a3cd9e in std::panicking::try::ha8bdfaa383f0ed33 /rustc/40336865fe7d4a01139a3336639c6971647e885c/library/std/src/panicking.rs:456:19
    #10 0x563927a3cd9e in std::panic::catch_unwind::ha58e9af879223892 /rustc/40336865fe7d4a01139a3336639c6971647e885c/library/std/src/panic.rs:137:14
    #11 0x563927a3cd9e in std::rt::lang_start_internal::_$u7b$$u7b$closure$u7d$$u7d$::h56456e42fba96b18 /rustc/40336865fe7d4a01139a3336639c6971647e885c/library/std/src/rt.rs:128:48
    #12 0x563927a3cd9e in std::panicking::try::do_call::h2bc188e30e56674d /rustc/40336865fe7d4a01139a3336639c6971647e885c/library/std/src/panicking.rs:492:40
    #13 0x563927a3cd9e in std::panicking::try::hc5e32e9b04c0821c /rustc/40336865fe7d4a01139a3336639c6971647e885c/library/std/src/panicking.rs:456:19
    #14 0x563927a3cd9e in std::panic::catch_unwind::h8f69e6799c52cea0 /rustc/40336865fe7d4a01139a3336639c6971647e885c/library/std/src/panic.rs:137:14
    #15 0x563927a3cd9e in std::rt::lang_start_internal::hd1476181c5102217 /rustc/40336865fe7d4a01139a3336639c6971647e885c/library/std/src/rt.rs:128:20

SUMMARY: AddressSanitizer: 8192 byte(s) leaked in 1 allocation(s).

However, running the correct version that deallocates gives me:

use std::alloc::{alloc, dealloc, Layout};

fn main() {
    type VecElement = u64;
    let size = 1024;

    let layout = Layout::from_size_align(size * std::mem::size_of::<VecElement>(), 64).unwrap();

    let mut my_vec = unsafe {
        let layout = Layout::from_size_align_unchecked(layout.size(), layout.align());
        println!("Size {}, Align {}", layout.size(), layout.align());
        let ptr = alloc(layout) as *mut VecElement;
        Vec::<VecElement>::from_raw_parts(ptr, 0, size)
    };

    my_vec.push(10);
    println!("{:?}", my_vec);

    unsafe {
        let ptr = my_vec.leak().as_mut_ptr() as *mut u8;
        dealloc(ptr, layout)
    }
}
Size 8192, Align 64
[10]

No error. This shows that it does indeed deallocate correctly.


WARNING

What you are doing is dangerous. You have to manually ensure that the vector actually gets deallocated through your dealloc function. There is zero compiler checks that you actually do this. This is a behaviour called unsound.

Possible solutions:

  • Provide a newtype wrapper that exposes only a sound subset of the Vec API for your usecase and ensures proper deallocation.
  • Use the nightly Vec::new_in() and Vec::with_capacity_in() methods that allow you to provide a custom allocator. Although that does mean that your crate now requires the nightly compiler.
  • Related