Безопасно ли приводить ссылки на прозрачные типы без размеров? - PullRequest
7 голосов
/ 26 апреля 2020

Атрибут #[repr(trasparent)] отмечает тип, имеющий макет того же типа, что и отдельное поле с ненулевым размером, но относится ли это к ссылкам / указателям указанных типов, когда типы не имеют размера?

В частности, могу ли я безопасно разыграть между &MySlice<T> и &[T] в приведенном ниже примере?

#[repr(transparent)]
struct MySlice<T>([T]);

let std_slice: &[i32] = &[ 1, 2, 3 ];

// is this safe?
let my_slice: &MySlice<i32> = unsafe {
    std::mem::transmute(std_slice)
};

1 Ответ

4 голосов
/ 26 апреля 2020

Согласно Rust Reference , одиночное поле struct с #[repr(transparent)] будет иметь одинаковое представление и ABI.

Это означает, что ABI &MySlice<T> совпадает с &[T], поскольку MySlice не имеет других полей, и поэтому мы можем рассматривать его так же, как [T]. Поэтому безопасно переходить между ними.

Однако то, как вы это делаете, нецелесообразно и может привести к ошибкам времени жизни, поскольку std::mem::transmute не сохраняет время жизни, если у его параметров типа есть время жизни, и при этом не выполняется приведение указателя, хотя приведение указателя обычно считается более безопасным, поскольку компилятор может вмешаться в случае ошибки.

Поэтому правильный способ создания &MySlice следующий:

#[repr(transparent)]
struct MySlice<T>([T]);

impl<T> MySlice<T> {
    pub fn make<'a>(value: &'a [T]) -> &'a Self {
        unsafe {
            &*(value as *const [T] as *const Self)
        }
    }
}

Детская площадка .
Это сохраняет срок службы и позволяет избежать transmute.


Кроме того, можно также использовать union s:

#[repr(transparent)]
struct MySlice<T>([T]);

union SliceRepr<'a, T> {
    slice: &'a [T],
    my_slice: &'a MySlice<T>,
}

impl<T> MySlice<T> {
    pub fn make<'a>(value: &'a [T]) -> &'a Self {
        unsafe {
            SliceRepr { slice: value }.my_slice
        }
    }
}

Поскольку это также заботится о время жизни.

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