如何在NonNull <opaque>中添加/减去偏移?

时间:2018-05-16 14:34:51

标签: rust

我提供了两个管理内存的功能:

unsafe extern "system" fn alloc<A: Alloc>(
    size: usize,
    alignment: usize,
) -> *mut c_void { ... }

unsafe extern "system" fn free<A: Alloc>(
    memory: *mut c_void
) { ... }

这两个函数在内部使用allocator-api

无法更改这些签名。问题是free没有要求sizealignment,这是Alloc::dealloc所必需的。为了解决这个问题,alloc为一个Layout分配了一些额外的空间。 free现在可以访问此Layout以获取所需的额外数据。

最近,allocator-api已更改,而*mut u8现在使用NonNull<Opaque>。这是我的问题发生的地方。

core::alloc::Opaque

  

不透明的非大小类型。用于指向已分配内存的指针。 [...]这样的指针类似于C的void*类型。

Opaque不是Sized,因此禁止使用NonNull::as_ptr().add()NonNull::as_ptr().sub()

以前,我使用过这样的东西(为简单起见,我假设Alloc的函数是静态的):

#![feature(allocator_api)]
#![no_std]

extern crate libc;

use core::alloc::{Alloc, Layout};
use libc::c_void;

unsafe extern "system" fn alloc<A: Alloc>(
    size: usize,
    alignment: usize,
) -> *mut c_void
{
    let requested_layout =
        Layout::from_size_align(size, alignment).unwrap();

    let (layout, padding) = Layout::new::<Layout>()
        .extend_packed(requested_layout)
        .unwrap();

    let ptr = A::alloc(layout).unwrap(); 
    (ptr as *mut Layout).write(layout);
    ptr.add(padding)
}

使用NonNull<Opaque>无法再使用最后一行。我怎么能绕过这个?

1 个答案:

答案 0 :(得分:1)

我可能会这样写,使用NonNull::as_ptr获取*mut Opaque,然后将其转换为不同的具体类型:

#![feature(allocator_api)]
#![no_std]

extern crate libc;

use core::alloc::{Alloc, Layout};
use libc::c_void;

unsafe fn alloc<A: Alloc>(allocator: &mut A, size: usize, alignment: usize) -> *mut c_void {
    let requested_layout = Layout::from_size_align(size, alignment).expect("Invalid layout");

    let (layout, _padding) = Layout::new::<Layout>()
        .extend_packed(requested_layout)
        .expect("Unable to create layout");

    let ptr = allocator.alloc(layout).expect("Unable to allocate");

    // Get a pointer to our layout storage 
    let raw = ptr.as_ptr() as *mut Layout;
    // Save it
    raw.write(layout);
    // Skip over it
    raw.offset(1) as *mut _
}
  

unsafe extern "system" fn alloc<A: Alloc>(

这对我没有意义。各种FFI ABI(“C”,“系统”等)无法指定Rust泛型类型。将此函数标记为extern似乎非常不正确。

  

Layout::new::<Layout>().extend_packed(requested_layout)

这似乎很可能非常破碎。正如documentation for Layout::extend_packed所述,强调我的:

  

next的对齐方式无关紧要,根本不会合并到生成的布局中

您返回的指针似乎不符合对齐请求。