Это UB, чтобы мутировать & T через * mut T в небезопасной ржавчине? - PullRequest
0 голосов
/ 04 мая 2019
let r = 42;
unsafe {
    let p = &r as *const i32 as *mut i32;
    *p += 1;
}
println!("{}", r);

Код выше UB?Есть ли вероятность, что rustc (при условии, что r является &i32) оптимизирует это таким образом, что в итоге получится UB?

Как насчет этого ↓

let rc = Rc::new(42);
unsafe {
    let p = &*rc as *const i32 as *mut i32;
    *p += 1;
}
println!("{}", rc);

Rc является однопоточным указателем подсчета ссылок, поэтому он не является потокобезопасным.
Если предположить, что вышеупомянутое выполняется в одном потоке, может ли оно закончиться как UB?

1 Ответ

2 голосов
/ 04 мая 2019

В обоих случаях определенно UB.

Основная проблема здесь заключается в том, что любые изменения значения за общей ссылкой являются недопустимыми, за исключением UnsafeCell внутренних значений. Компилятор может легко оптимизировать изменение в первом случае и просто подставить r в println вызов.

Второй случай немного сложнее, но основан на том же факте. Обратите внимание, что выражение &*r, где r имеет тип Rc<T>, имеет тип & T ( детская площадка ):

use std::rc::Rc;

fn test<T>(r: Rc<T>) {
    let _: () = &*r; // error: expected (), found &T
}

Хитрость в том, что Rc<T> обращается к T, поэтому *r имеет тип T.

Итак, это снова неизменяемая ссылка, которая рассматривается как изменяемая.

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