ptr_ds/
rawptr.rs

1//! 生ポインタ。
2//!
3//! ## Preliminaries
4//!
5//! ### 参照とポインタの作成
6//!
7//! Safe Rust においては、下記のようなコードはコンパイルエラーとなる。
8//!
9//! ```compile_fail
10//! let mut a = 1;
11//! let mut_ref_1 = &mut a;
12//! let mut_ref_2 = &mut *mut_ref_1;
13//! *mut_ref_2 = 2;
14//! *mut_ref_1 = 3;
15//! let _invalid = *mut_ref_2; // (!)
16//! ```
17//!
18//! Unsafe Rust において、生ポインタを使うことで、コンパイルを通すことはできる。
19//!
20//! ```ignore
21//! let mut a = 1_u32;
22//! let mut_ref_1 = &mut a;
23//! let mut_ref_2 = unsafe { &mut *(mut_ref_1 as *mut u32) };
24//! *mut_ref_2 = 2;
25//! *mut_ref_1 = 3;
26//! let _invalid = *mut_ref_2; // (?)
27//! ```
28//!
29//! ただし、(たとえば C++ がそうであるように)コンパイルが通り、プログラムが正常終了したというのは、
30//! コードに問題がないということの証明にはならない。実際、Miri でテストすることで未定義動作が検出され、
31//! 次のような出力が得られるであろう。
32//!
33//! ```zsh
34//! % cargo miri test
35//! ```
36//!
37//! ```txt
38//! error: Undefined Behavior: attempting a read access using <90194> at alloc23256[0x0], but that tag does not exist in the borrow stack for this location
39//!  --> src/lib.rs:8:20
40//!   |
41//! 8 |     let _invalid = *mut_ref_2; // (?)
42//!   |                    ^^^^^^^^^^
43//!   |                    |
44//!   |                    attempting a read access using <90194> at alloc23256[0x0], but that tag does not exist in the borrow stack for this location
45//!   |                    this error occurs as part of an access at alloc23256[0x0..0x4]
46//! ```
47//!
48//! こうした検出は Stacked Borrows と呼ばれる機構によって行われている。
49//! Miri では Stacked Borrows のサポートは experimental とのことであるが、一旦はこれを信用することにする。
50//!
51//! さて、safe なスマートポインタとして [`Box`] があるので、それを使ってみよう。
52//!
53//! ```
54//! struct Foo(u32);
55//! impl Foo {
56//!     pub fn new() -> Self { Foo(0) }
57//! }
58//!
59//! let mut foo = Box::new(Foo::new());
60//! assert_eq!(foo.0, 0);
61//! foo.0 = 10;
62//! assert_eq!(foo.0, 10);
63//! ```
64//!
65//! [`Box::leak`] を用いることで [`&'a mut T`][reference] を取り出すことができる。
66//!
67//! ```ignore
68//! # struct Foo(u32);
69//! # impl Foo {
70//! #     pub fn new() -> Self { Foo(0) }
71//! # }
72//! let foo = Box::new(Foo::new());
73//! let foo_mut_ref = Box::leak(foo);
74//! assert_eq!(foo_mut_ref.0, 0);
75//! foo_mut_ref.0 = 10;
76//! assert_eq!(foo_mut_ref.0, 10);
77//! // (?)
78//! ```
79//!
80//! [`&'a mut T`][reference] は、生ポインタ (raw pointer) [`*mut T`][pointer] にキャストすることもできる。
81//! 参照外し (dereference) は `unsafe` となる。
82//!
83//! ```ignore
84//! # struct Foo(u32);
85//! # impl Foo {
86//! #     pub fn new() -> Self { Foo(0) }
87//! # }
88//! let foo = Box::new(Foo::new());
89//! let foo_mut_ptr: *mut _ = Box::leak(foo);
90//! assert_eq!(unsafe { (*foo_mut_ptr).0 }, 0);
91//! unsafe { (*foo_mut_ptr).0 = 10 };
92//! assert_eq!(unsafe { (*foo_mut_ptr).0 }, 10);
93//! // (?)
94//! ```
95//!
96//! ところで、スマートポインタから生ポインタを取り出したままだと、drop
97//! されないのでメモリリークしてしまう。
98//! これも Miri によって検出でき、次のような出力が得られるであろう。
99//!
100//! ```txt
101//! error: memory leaked: alloc23417 (Rust heap, size: 4, align: 4), allocated here:
102//!   --> .../lib/rustlib/src/rust/library/alloc/src/alloc.rs:98:9
103//!    |
104//! 98 |         __rust_alloc(layout.size(), layout.align())
105//!    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
106//! ```
107//!
108//! [`Box::into_raw`] にある例に従い、次のようにすることで、`Box` 側に destructor を呼ばせることができる。
109//! 逆に、勝手に destructor を呼ばれると困るような状況においては、`Box` を使うと厄介なことになる。
110//!
111//! ```
112//! # struct Foo(u32);
113//! # impl Foo {
114//! #     pub fn new() -> Self { Foo(0) }
115//! # }
116//! let foo_mut_ptr: *mut _ = Box::leak(Box::new(Foo::new()));
117//! unsafe { drop(Box::from_raw(foo_mut_ptr)) };
118//! ```
119//!
120//! [`*mut T`][pointer] の代わりに [`std::ptr::NonNull`] を用いることもできる。
121//!
122//! ```
123//! use std::ptr::NonNull;
124//!
125//! # struct Foo(u32);
126//! # impl Foo {
127//! #     pub fn new() -> Self { Foo(0) }
128//! # }
129//! let foo_mut_ref = Box::leak(Box::new(Foo::new()));
130//! let foo_nonnull = NonNull::from(foo_mut_ref);
131//! unsafe { drop(Box::from_raw(foo_nonnull.as_ptr())) };
132//! ```
133//!
134//! `*mut T` に対する `NonNull` の違いは、null でないことの他に covariant
135//! であることが挙げられるが、これに関しては [`variance`] を参照せよ。
136//!
137//! [`variance`]: ../variance/index.html
138//!
139//! ## See also
140//! - [rust-lang / **miri**](https://github.com/rust-lang/miri)
141
142#[test]
143#[ignore]
144fn invalidate() {
145    struct Foo(u32, u32);
146    let mut foo = Foo(10, 20);
147    let foo_mut: *mut _ = &mut foo;
148    unsafe { (*foo_mut).0 += 1 };
149    unsafe { assert_eq!((*foo_mut).0, 11) };
150    // let foo_const: *const _ = &foo;
151    let foo_const = &foo;
152    unsafe {
153        let _foo = &(*foo_mut);
154    }
155    assert_eq!(foo.0, 11);
156    // unsafe { assert_eq!((*foo_const).1, 20) };
157    assert_eq!(foo_const.1, 20);
158    unsafe { (*foo_mut).0 += 1 }; // UB detected when using -Zmiri-tree-borrows
159    unsafe { assert_eq!((*foo_mut).0, 12) };
160}