Создание указателя c_void в Rust - PullRequest
0 голосов
/ 09 мая 2020

У меня есть функция с вводом типа ptr::NonNull<c_void>. Обычно этот ввод предоставляется кодом C. Допустимый ввод имеет тип: &(int){5}.

Однако мне нужно создать несколько входов в Rust. Итак, я сделал следующее:

let i = 5;
let data = &i as *const u32;
ptr::NonNull::new_unchecked(data as *mut _)

В случае ввода le git из кода C выполняется следующий блок:

ptr::NonNull::new_unchecked(x.data as *mut _)

где x.data происходит от struct, где x имеет тип X:

#[repr(C)]
pub struct X {
    data: *const c_void,
}

Для справки, код вместе выглядит примерно так:

if x.data.is_null() {
    let i = 5;
    let data = &i as *const u32;
    ptr::NonNull::new_unchecked(data as *mut _)
} else {
    // x.data is specified in C code through FFI as &(int){5}
    ptr::NonNull::new_unchecked(x.data as *mut _)
}

Однако, когда я пытаюсь разыменовать значение на более позднем этапе для ветви else я получаю 5, как и ожидалось. Но для ветки if я получаю большое мусорное значение. Я предполагаю, что это связано с тем, как я создаю необработанный указатель в Rust.

1 Ответ

4 голосов
/ 09 мая 2020

В ветке if вы создаете переменную с локальной областью видимости i, получаете указатель (ссылку) на нее и передаете эту ссылку на new_unchecked, который не копирует ваши данные, а просто инкапсулирует указатель, который затем вы переходите за пределы своей области действия.

Позже в программе вы пытаетесь получить доступ к данным, которые больше не входят в область действия, и, таким образом, вы получаете неопределенные данные.

Попробуйте определить данные в Box и используйте into_raw(), чтобы получить указатель

РЕДАКТИРОВАТЬ: На самом деле, что-то вроде этого может быть лучше:

let val = if x.data.is_null() {
    5
} else {
    *x.data
};
let data = &val as *const u32;
ptr::NonNull::new_unchecked(data as *mut _)

который берет выделение из ограничивающего блока.

...