Как заставить Rust стать владельцем выделенной памяти, кроме как ее безопасными методами? - PullRequest
0 голосов
/ 24 февраля 2019

В своей февральской заметке 2018 года под названием « Безопасность памяти в Rust: тематическое исследование с C » Уилл Крайтон писал:

Rust дает возможность стать владельцем необработанногоуказатели, которые мы используем, используя slice::from_raw_parts_mut и Box::from_raw, что говорит Rust обрабатывать указатель памяти как массив, выделенный из кучи.После передачи права собственности, предполагая, что память действительна и имеет правильный размер / тип, Rust применяет свои обычные проверки безопасности и защиты памяти.

Соответствующая часть его кода, к которой относится вышеуказанное:

let mut new_data = unsafe {
    let ptr = Heap::default()
        .alloc(Layout::array::<isize>(new_capacity).unwrap())
        .unwrap() as *mut isize;
    Box::from_raw(slice::from_raw_parts_mut(ptr, new_capacity))
};

Однако, документация для Box::from_raw гласит (выделение добавлено):

Поскольку способ, которым Box выделяет и освобождает память, не указан, единственный действительный указатель для передачи этой функции - это тот, который взят из другого ящика с помощью функции Box::into_raw.

ДляВо избежание сомнений, (экспериментальный) Heap API, использованный выше для выполнения выделения памяти (так как удален в Rust 1.27.0), напрямую вызывается __rust_alloc в его alloc методе- и поэтому ptr было не получено из Box::into_raw.

Допустимо ли, хотя и не поддерживается, передавать Box::from_raw необработанные указатели на только что выделенную память, чтобы иметь Rustвзять на себя ответственность за эту память и обеспечить егообычные проверки безопасности и сдерживания?В частности, будет ли Rust освобождать эту память при уничтожении возникающего бокса?

Если нет, то как может один заставить Rust получить такое владение памятью, выделенной не его безопасными методами?

1 Ответ

0 голосов
/ 25 февраля 2019

Допустимо ли, хотя и не поддерживается, передавать Box::from_raw необработанные указатели в только что выделенную память

Нет, это недопустимо.

В частности, освободит ли Rust эту память при уничтожении возникающего Box?

Да, и это причина того, что она недействительна.

Распределители памяти предоставляют в паре процедуры выделения и освобождения.Когда вы выделяете часть памяти одним распределителем, , вы должны освободить его этим распределителем .

Если вы этого не сделаете, когда распределитель, выполняющий освобождение, пойдет на выполнение какой бы то ни было бухгалтерской работы, он не будет знать об этом куске памяти.Распределитель, который фактически выполнил выделение, никогда не пометит эту память как недоступную.

Эти проблемы также не решены.Я отправил исправления в GLib , чтобы исправить места, где произошли несоответствующие распределения / освобождения и вызвали реальные проблемы в дикой природе.

На уровне необработанных указателей владение в значительной степени является состоянием ума, как в C или C ++.Для собственного что-то здесь означает, что вы несете ответственность за его надлежащую очистку.

malloc и free являются парными методами распределения / освобождения.Вы можете создать свой собственный тип и реализовать для него Drop:

use libc::{free, malloc};
use std::{ffi::c_void, mem};

struct MallocBox(*mut i32);

impl MallocBox {
    fn new(v: i32) -> Self {
        unsafe {
            let p = malloc(mem::size_of::<i32>()) as *mut i32;
            *p = v;
            Self(p)
        }
    }
}

impl Drop for MallocBox {
    fn drop(&mut self) {
        unsafe { free(self.0 as *mut c_void) }
    }
}

fn main() {
    MallocBox::new(42);
}

Реальная реализация также реализует Deref и, возможно, многие другие черты, так что этот тип эргономичен для использования.

Было бы неприятно создавать MallocBox и JeMallocBox и MyCustomAllocBox, поэтому RFC 1398 предлагает общую черту для распределителей.Связанные работы продвигаются для преобразования Box<T> в Box<T, A: Alloc + Default = Global>.

как можно заставить Rust

Нет понятия "принуждение"Ржавчина, чтобы сделать что-нибудь, тем более, когда дело доходит до деталей низкого уровня, как это.Например, нет гарантии, что код C, который выделил указатель, не пытается освободить сам указатель.В мире FFI право собственности является соглашением о сотрудничестве.


См. Также:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...