SlideShare una empresa de Scribd logo
1 de 23
2019/03/25 Rust LT #3
後藤 弘明
The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)
 Rust 歴 4ヶ月ぐらい
 OSS で regtail を開発中
https://github.com/StoneDot/regtail
 某ソシャゲ会社でサーバーエンジニア
 仕事ではPHPを使っている
@StoneDot
The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)
 Future, Generator のためには自己参照する構造体を扱いたい
 しかし、自己参照する構造体は Move すると不正な状態に陥る
value pointer
元居た領域 value pointer
ポインタが古い領域を示してしまう
Move
The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)
 大きさ2の配列を受け取り、いずれかの要素を選択する構造体
 構造体作成時には0番目の要素を選択
 toggle を使って選択要素を切り替え
 get, set で値の取得と変更ができる
impl SelfRef {
pub fn new(ary: [i32; 2]) -> Pin<Box<SelfRef>> { ... }
pub fn toggle(self) { ... }
pub fn get(self) -> i32 { ... }
pub fn set(self, value: i32) { ... }
}
The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)
 関数をまたがなければ参照で安全にできる(つまり使いものにならない)
 参照における制約(1 mutable borrow)は引き継ぐ(Read Only ならば OK)
let mut ary = [1, 2];
let mut data = SelfRef { ary, ptr: &ary[0] };
data.ptr = &data.ary[0];
data.ptr = &data.ary[1];
#[derive(Debug)]
struct SelfRef<'a> {
ary: [i32; 2],
ptr: &'a i32,
}
*data.ptr = 10; こういった値の書き換えはできない
The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)
 関数またいで使えないとかイケてないし、参照先も書き換えたい
 Pointer 使えば良いじゃん!
 unsafe だけどこれは流石に安全だよね?
#[derive(Debug)]
struct SelfRef {
ary: [i32; 2],
ptr: NonNull<i32>,
}
impl SelfRef {
fn get(self: &Self) -> i32 {
unsafe {
*self.ptr.as_ref()
}
}
}
The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)
 全然安全ではありません! Moveした瞬間死にます
-919602312 コンストラクタで move するので即死
impl SelfRef {
fn new() -> SelfRef {
let mut data = SelfRef { ary: [1, 2], ptr: NonNull::dangling() };
data.ptr = NonNull::from(&data.ary[0]);
data
}
}
let mut data = SelfRef::new();
println!("{:?}", data.get());
The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)
 BOX化すればアドレスは基本変わらないので、安全なはず!
impl SelfRef {
fn new(ary: [i32; 2]) -> Box<SelfRef> {
let data = SelfRef { ary, ptr: NonNull::dangling() };
let mut boxed = Box::new(data);
boxed.ptr = NonNull::from(&boxed.ary[0]);
boxed
}
}
struct SelfRef {
ary: [i32; 2],
pub ptr: NonNull<i32>,
}
デバッグのためにつけた
The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)
 std::mem::swap, std::mem::replace みたいなことをされると死ぬ
let mut data1 = SelfRef::new([1, 2]);
let mut data2 = SelfRef::new([3, 4]);
std::mem::swap(data1.as_mut(), data2.as_mut());
unsafe { *data1.ptr.as_mut() = 100; }
println!("{} {}", data1.ary[0], data1.ary[1]);
println!("{} {}", data2.ary[0], data2.ary[1]);
3 4
100 2
data1 を書き換えたつもりが、data2 が変わっている
100 4
1 2
本当は みたいになって欲しい
The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)
 参照を使うとデータの中身を変化させられない&関数跨げない
 1 mutable borrow の制約からの自然な帰結
 関数を跨げないので基本的に使い物にならない
 NonNull<T>で自己参照できるけど……
 Moveされるだけで簡単にダングリングポインタになっちゃう
 Box化すればヒープにいるから基本大丈夫だけど、std::mem::swapとかで死ぬ
 &mut が取り出せちゃうと move, swap などを止めることが出来ないのが最大の原因
 Move禁止を強制したいけどどうすればいいんだ!
The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)
 Pinされたオブジェクトの mutable reference の取得は安全でない!
 なぜなら std::mem::swap で move される危険があるため
 Pinされたオブジェクトは、
 unsafeコード以外からは mutable reference を取得できない
 safe関数でラップして通常操作での安全性を担保する
 immutable reference の取得は問題なく行える
 immutable reference からは move をすることができないため
つまり Pin されたオブジェクトは以下のように振る舞えば良い
The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)
 Pinしていても自由にMoveできる構造体には Unpin (auto-trait) がついている
 普通に構造体を作ると Unpin が勝手につくので Move 可能な構造体として振る舞う
 get_mut() で mutable reference が取れてしまう
 扱う構造体が move に対して安全じゃない場合は構造体に
std::marker::PhantomPinned を持たせることで Unpin を opt-out する必要がある
struct SelfRef {
ary: [i32; 2],
ptr: NonNull<i32>,
_pin: PhantomPinned
}
SelfRefはPinされているときにMoveを
安全に行うことが出来ないことを宣言
The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)
 Box::pin, Rc::pin, Arc::pin でPINされたスマートポインタを作れる
impl SelfRef {
fn new(ary: [i32; 2]) -> Pin<Box<SelfRef>> {
let data = SelfRef { ary, ptr: NonNull::dangling(), _pin: PhantomPinned };
let mut boxed = Box::pin(data);
let ptr = NonNull::from(&boxed.ary[0]);
unsafe {
boxed.as_mut().get_unchecked_mut().ptr = ptr;
}
boxed
}
}
The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)
 unsafe コードを通してデータを変更
impl SelfRef {
fn new(ary: [i32; 2]) -> Pin<Box<SelfRef>> {
let data = SelfRef { ary, ptr: NonNull::dangling(), _pin: PhantomPinned };
let mut boxed = Box::pin(data);
let ptr = NonNull::from(&boxed.ary[0]);
unsafe {
boxed.as_mut().get_unchecked_mut().ptr = ptr;
}
boxed
}
}
The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)
 unsafe部分を分解して、型を追いかける
unsafe {
boxed.as_mut().get_unchecked_mut().ptr = ptr;
}
unsafe {
let mut_ref = boxed.as_mut();
let mut_obj = mut_ref.get_unchecked_mut();
mut_obj.ptr = ptr;
}
等価な変換
Pin<Box<SelfRef>>を
Pin<&mut SelfRef> に変換
&mut SelfRef に変換 (unsafe)
&mut SelfRef を変更
The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)
 get は deref が効くので self をとって処理をすることができる
 set は &mut Pin<Box<Self>> が必要なのでselfを使ったメソッド構文が使えない
 Pin<Box<Self>>, Arc<Self> などはできるようになってます (v1.33)
 arbitrary_self_types を使えばできる (nightly)
pub fn get(&self) -> i32 {
unsafe { *self.ptr.as_ref() }
}
pub fn set(target: &mut Pin<Box<Self>>, value: i32) {
unsafe { *target.as_mut().get_unchecked_mut().ptr.as_mut() = value; }
}
The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)
 setと同じくPin<Box<Self>>が必要なので、メソッド呼び出し構文は使用不可
pub fn toggle(target: &mut Pin<Box<Self>>) {
let ptr;
if NonNull::from(&target.ary[0]) == target.ptr {
ptr = NonNull::from(&target.ary[1]);
} else {
ptr = NonNull::from(&target.ary[0]);
}
unsafe {
target.as_mut().get_unchecked_mut().ptr = ptr;
}
}
The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)
 SelfRef::set, SelfRef::toggle は通常の関数呼び出しを使う必要がある
 struct ToggleInt { inner: Pin<Box<SelfRef>> } のように別構造体で包めば、
使いやすいインターフェースを提供することも可能
let mut data = SelfRef::new([1, 2]);
assert_eq!(1, data.get());
SelfRef::set(&mut data, 100);
assert_eq!(100, data.get());
SelfRef::toggle(&mut data);
assert_eq!(2, data.get());
SelfRef::toggle(&mut data);
assert_eq!(100, data.get());
The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)
 std::pin を使うと move 不可なオブジェクトが作れる
 std::pin を使うのに unsafe コードは必須
 必要性が薄いなら別実装を考えたほうが良いかも
 Pin<Box<T>> を生で扱うとインターフェースが汚くなるので注意
 Pin<Box<T>> ならメソッドレシーバーにできるけど、&mut Pin<Box<T>> とかはまだ無
理
 キレイなインターフェース版は GitHub においておきます
https://github.com/StoneDot/toggle-int

Más contenido relacionado

La actualidad más candente

Parser combinatorってなんなのさ
Parser combinatorってなんなのさParser combinatorってなんなのさ
Parser combinatorってなんなのさcct-inc
 
できる!並列・並行プログラミング
できる!並列・並行プログラミングできる!並列・並行プログラミング
できる!並列・並行プログラミングPreferred Networks
 
RSA暗号運用でやってはいけない n のこと #ssmjp
RSA暗号運用でやってはいけない n のこと #ssmjpRSA暗号運用でやってはいけない n のこと #ssmjp
RSA暗号運用でやってはいけない n のこと #ssmjpsonickun
 
SQL大量発行処理をいかにして高速化するか
SQL大量発行処理をいかにして高速化するかSQL大量発行処理をいかにして高速化するか
SQL大量発行処理をいかにして高速化するかShogo Wakayama
 
Dockerfile を書くためのベストプラクティス解説編
Dockerfile を書くためのベストプラクティス解説編Dockerfile を書くためのベストプラクティス解説編
Dockerfile を書くためのベストプラクティス解説編Masahito Zembutsu
 
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!mosa siru
 
組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門Norishige Fukushima
 
JavaScript難読化読経
JavaScript難読化読経JavaScript難読化読経
JavaScript難読化読経Yosuke HASEGAWA
 
ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14Ryo Suzuki
 
TRICK 2022 Results
TRICK 2022 ResultsTRICK 2022 Results
TRICK 2022 Resultsmametter
 
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Kohei Tokunaga
 
非同期処理の基礎
非同期処理の基礎非同期処理の基礎
非同期処理の基礎信之 岩永
 
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture世界一わかりやすいClean Architecture
世界一わかりやすいClean ArchitectureAtsushi Nakamura
 
関数型プログラミングのデザインパターンひとめぐり
関数型プログラミングのデザインパターンひとめぐり関数型プログラミングのデザインパターンひとめぐり
関数型プログラミングのデザインパターンひとめぐりKazuyuki TAKASE
 
中3女子でもわかる constexpr
中3女子でもわかる constexpr中3女子でもわかる constexpr
中3女子でもわかる constexprGenya Murakami
 
Pythonによる黒魔術入門
Pythonによる黒魔術入門Pythonによる黒魔術入門
Pythonによる黒魔術入門大樹 小倉
 
これから Haskell を書くにあたって
これから Haskell を書くにあたってこれから Haskell を書くにあたって
これから Haskell を書くにあたってTsuyoshi Matsudate
 
多段階計算の型システムの基礎
多段階計算の型システムの基礎多段階計算の型システムの基礎
多段階計算の型システムの基礎T. Suwa
 

La actualidad más candente (20)

Docker Compose 徹底解説
Docker Compose 徹底解説Docker Compose 徹底解説
Docker Compose 徹底解説
 
Parser combinatorってなんなのさ
Parser combinatorってなんなのさParser combinatorってなんなのさ
Parser combinatorってなんなのさ
 
できる!並列・並行プログラミング
できる!並列・並行プログラミングできる!並列・並行プログラミング
できる!並列・並行プログラミング
 
RSA暗号運用でやってはいけない n のこと #ssmjp
RSA暗号運用でやってはいけない n のこと #ssmjpRSA暗号運用でやってはいけない n のこと #ssmjp
RSA暗号運用でやってはいけない n のこと #ssmjp
 
SQL大量発行処理をいかにして高速化するか
SQL大量発行処理をいかにして高速化するかSQL大量発行処理をいかにして高速化するか
SQL大量発行処理をいかにして高速化するか
 
Dockerfile を書くためのベストプラクティス解説編
Dockerfile を書くためのベストプラクティス解説編Dockerfile を書くためのベストプラクティス解説編
Dockerfile を書くためのベストプラクティス解説編
 
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!
 
組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門
 
TLS, HTTP/2演習
TLS, HTTP/2演習TLS, HTTP/2演習
TLS, HTTP/2演習
 
JavaScript難読化読経
JavaScript難読化読経JavaScript難読化読経
JavaScript難読化読経
 
ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14
 
TRICK 2022 Results
TRICK 2022 ResultsTRICK 2022 Results
TRICK 2022 Results
 
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Dockerからcontainerdへの移行
Dockerからcontainerdへの移行
 
非同期処理の基礎
非同期処理の基礎非同期処理の基礎
非同期処理の基礎
 
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
 
関数型プログラミングのデザインパターンひとめぐり
関数型プログラミングのデザインパターンひとめぐり関数型プログラミングのデザインパターンひとめぐり
関数型プログラミングのデザインパターンひとめぐり
 
中3女子でもわかる constexpr
中3女子でもわかる constexpr中3女子でもわかる constexpr
中3女子でもわかる constexpr
 
Pythonによる黒魔術入門
Pythonによる黒魔術入門Pythonによる黒魔術入門
Pythonによる黒魔術入門
 
これから Haskell を書くにあたって
これから Haskell を書くにあたってこれから Haskell を書くにあたって
これから Haskell を書くにあたって
 
多段階計算の型システムの基礎
多段階計算の型システムの基礎多段階計算の型システムの基礎
多段階計算の型システムの基礎
 

Similar a std::pin の勘所

katagaitai CTF勉強会 #5 Crypto
katagaitai CTF勉強会 #5 Cryptokatagaitai CTF勉強会 #5 Crypto
katagaitai CTF勉強会 #5 Cryptotrmr
 
httpd.conf line 1 to 7, 24
httpd.conf line 1 to 7, 24httpd.conf line 1 to 7, 24
httpd.conf line 1 to 7, 24Naoya Nakazawa
 
インメモリーで超高速処理を実現する場合のカギ
インメモリーで超高速処理を実現する場合のカギインメモリーで超高速処理を実現する場合のカギ
インメモリーで超高速処理を実現する場合のカギMasaki Yamakawa
 
LagopusとAzureとIPsecとDPDK
LagopusとAzureとIPsecとDPDKLagopusとAzureとIPsecとDPDK
LagopusとAzureとIPsecとDPDKTomoya Hibi
 
フラッター開発におけるシークレット情報取扱考察
フラッター開発におけるシークレット情報取扱考察フラッター開発におけるシークレット情報取扱考察
フラッター開発におけるシークレット情報取扱考察cch-robo
 
ハードウェアによる仮想化支援機能を利用したハイパバイザーIPS
ハードウェアによる仮想化支援機能を利用したハイパバイザーIPSハードウェアによる仮想化支援機能を利用したハイパバイザーIPS
ハードウェアによる仮想化支援機能を利用したハイパバイザーIPSFFRI, Inc.
 
Kanazawa.js.Next
Kanazawa.js.NextKanazawa.js.Next
Kanazawa.js.Nextdynamis
 
HaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミングHaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミングKiwamu Okabe
 
そろそろRStudioの話
そろそろRStudioの話そろそろRStudioの話
そろそろRStudioの話Kazuya Wada
 
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519Yasuhiro Ishii
 
Postgre sql9.3 newlockmode_and_etc
Postgre sql9.3 newlockmode_and_etcPostgre sql9.3 newlockmode_and_etc
Postgre sql9.3 newlockmode_and_etckasaharatt
 
Lagopusで試すFirewall
Lagopusで試すFirewallLagopusで試すFirewall
Lagopusで試すFirewallTomoya Hibi
 
Indy(Invokedynamic) and Bytecode DSL and Brainf*ck
Indy(Invokedynamic) and Bytecode DSL and Brainf*ckIndy(Invokedynamic) and Bytecode DSL and Brainf*ck
Indy(Invokedynamic) and Bytecode DSL and Brainf*ckUehara Junji
 
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„和弘 井之上
 
Uart受信設計2013
Uart受信設計2013Uart受信設計2013
Uart受信設計2013Kiyoshi Ogawa
 
YAPC Asia 2010 30days Albumの裏側 後日談
YAPC Asia 2010 30days Albumの裏側 後日談YAPC Asia 2010 30days Albumの裏側 後日談
YAPC Asia 2010 30days Albumの裏側 後日談Kensuke Nagae
 

Similar a std::pin の勘所 (20)

katagaitai CTF勉強会 #5 Crypto
katagaitai CTF勉強会 #5 Cryptokatagaitai CTF勉強会 #5 Crypto
katagaitai CTF勉強会 #5 Crypto
 
httpd.conf line 1 to 7, 24
httpd.conf line 1 to 7, 24httpd.conf line 1 to 7, 24
httpd.conf line 1 to 7, 24
 
インメモリーで超高速処理を実現する場合のカギ
インメモリーで超高速処理を実現する場合のカギインメモリーで超高速処理を実現する場合のカギ
インメモリーで超高速処理を実現する場合のカギ
 
LagopusとAzureとIPsecとDPDK
LagopusとAzureとIPsecとDPDKLagopusとAzureとIPsecとDPDK
LagopusとAzureとIPsecとDPDK
 
フラッター開発におけるシークレット情報取扱考察
フラッター開発におけるシークレット情報取扱考察フラッター開発におけるシークレット情報取扱考察
フラッター開発におけるシークレット情報取扱考察
 
ハードウェアによる仮想化支援機能を利用したハイパバイザーIPS
ハードウェアによる仮想化支援機能を利用したハイパバイザーIPSハードウェアによる仮想化支援機能を利用したハイパバイザーIPS
ハードウェアによる仮想化支援機能を利用したハイパバイザーIPS
 
Kanazawa.js.Next
Kanazawa.js.NextKanazawa.js.Next
Kanazawa.js.Next
 
HaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミングHaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミング
 
そろそろRStudioの話
そろそろRStudioの話そろそろRStudioの話
そろそろRStudioの話
 
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519
 
Postgre sql9.3 newlockmode_and_etc
Postgre sql9.3 newlockmode_and_etcPostgre sql9.3 newlockmode_and_etc
Postgre sql9.3 newlockmode_and_etc
 
Aerospike deep dive LDTs
Aerospike deep dive LDTsAerospike deep dive LDTs
Aerospike deep dive LDTs
 
Lagopusで試すFirewall
Lagopusで試すFirewallLagopusで試すFirewall
Lagopusで試すFirewall
 
Indy(Invokedynamic) and Bytecode DSL and Brainf*ck
Indy(Invokedynamic) and Bytecode DSL and Brainf*ckIndy(Invokedynamic) and Bytecode DSL and Brainf*ck
Indy(Invokedynamic) and Bytecode DSL and Brainf*ck
 
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„
 
Uart受信設計2013
Uart受信設計2013Uart受信設計2013
Uart受信設計2013
 
YAPC Asia 2010 30days Albumの裏側 後日談
YAPC Asia 2010 30days Albumの裏側 後日談YAPC Asia 2010 30days Albumの裏側 後日談
YAPC Asia 2010 30days Albumの裏側 後日談
 
Prosym2012
Prosym2012Prosym2012
Prosym2012
 
Puppet on AWS
Puppet on AWSPuppet on AWS
Puppet on AWS
 
Windows と leopard
Windows と leopardWindows と leopard
Windows と leopard
 

Último

CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?
CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?
CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?akihisamiyanaga1
 
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)Hiroshi Tomioka
 
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdfクラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdfFumieNakayama
 
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...博三 太田
 
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)NTT DATA Technology & Innovation
 
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdfAWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdfFumieNakayama
 
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)UEHARA, Tetsutaro
 
自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer
自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer
自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineerYuki Kikuchi
 

Último (8)

CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?
CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?
CTO, VPoE, テックリードなどリーダーポジションに登用したくなるのはどんな人材か?
 
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
 
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdfクラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
 
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...
 
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
 
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdfAWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
 
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
 
自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer
自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer
自分史上一番早い2024振り返り〜コロナ後、仕事は通常ペースに戻ったか〜 by IoT fullstack engineer
 

std::pin の勘所

  • 1. 2019/03/25 Rust LT #3 後藤 弘明
  • 2. The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)  Rust 歴 4ヶ月ぐらい  OSS で regtail を開発中 https://github.com/StoneDot/regtail  某ソシャゲ会社でサーバーエンジニア  仕事ではPHPを使っている @StoneDot
  • 3.
  • 4.
  • 5. The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)  Future, Generator のためには自己参照する構造体を扱いたい  しかし、自己参照する構造体は Move すると不正な状態に陥る value pointer 元居た領域 value pointer ポインタが古い領域を示してしまう Move
  • 6.
  • 7. The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)  大きさ2の配列を受け取り、いずれかの要素を選択する構造体  構造体作成時には0番目の要素を選択  toggle を使って選択要素を切り替え  get, set で値の取得と変更ができる impl SelfRef { pub fn new(ary: [i32; 2]) -> Pin<Box<SelfRef>> { ... } pub fn toggle(self) { ... } pub fn get(self) -> i32 { ... } pub fn set(self, value: i32) { ... } }
  • 8. The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)  関数をまたがなければ参照で安全にできる(つまり使いものにならない)  参照における制約(1 mutable borrow)は引き継ぐ(Read Only ならば OK) let mut ary = [1, 2]; let mut data = SelfRef { ary, ptr: &ary[0] }; data.ptr = &data.ary[0]; data.ptr = &data.ary[1]; #[derive(Debug)] struct SelfRef<'a> { ary: [i32; 2], ptr: &'a i32, } *data.ptr = 10; こういった値の書き換えはできない
  • 9. The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)  関数またいで使えないとかイケてないし、参照先も書き換えたい  Pointer 使えば良いじゃん!  unsafe だけどこれは流石に安全だよね? #[derive(Debug)] struct SelfRef { ary: [i32; 2], ptr: NonNull<i32>, } impl SelfRef { fn get(self: &Self) -> i32 { unsafe { *self.ptr.as_ref() } } }
  • 10. The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)  全然安全ではありません! Moveした瞬間死にます -919602312 コンストラクタで move するので即死 impl SelfRef { fn new() -> SelfRef { let mut data = SelfRef { ary: [1, 2], ptr: NonNull::dangling() }; data.ptr = NonNull::from(&data.ary[0]); data } } let mut data = SelfRef::new(); println!("{:?}", data.get());
  • 11. The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)  BOX化すればアドレスは基本変わらないので、安全なはず! impl SelfRef { fn new(ary: [i32; 2]) -> Box<SelfRef> { let data = SelfRef { ary, ptr: NonNull::dangling() }; let mut boxed = Box::new(data); boxed.ptr = NonNull::from(&boxed.ary[0]); boxed } } struct SelfRef { ary: [i32; 2], pub ptr: NonNull<i32>, } デバッグのためにつけた
  • 12. The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)  std::mem::swap, std::mem::replace みたいなことをされると死ぬ let mut data1 = SelfRef::new([1, 2]); let mut data2 = SelfRef::new([3, 4]); std::mem::swap(data1.as_mut(), data2.as_mut()); unsafe { *data1.ptr.as_mut() = 100; } println!("{} {}", data1.ary[0], data1.ary[1]); println!("{} {}", data2.ary[0], data2.ary[1]); 3 4 100 2 data1 を書き換えたつもりが、data2 が変わっている 100 4 1 2 本当は みたいになって欲しい
  • 13. The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)  参照を使うとデータの中身を変化させられない&関数跨げない  1 mutable borrow の制約からの自然な帰結  関数を跨げないので基本的に使い物にならない  NonNull<T>で自己参照できるけど……  Moveされるだけで簡単にダングリングポインタになっちゃう  Box化すればヒープにいるから基本大丈夫だけど、std::mem::swapとかで死ぬ  &mut が取り出せちゃうと move, swap などを止めることが出来ないのが最大の原因  Move禁止を強制したいけどどうすればいいんだ!
  • 14.
  • 15. The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)  Pinされたオブジェクトの mutable reference の取得は安全でない!  なぜなら std::mem::swap で move される危険があるため  Pinされたオブジェクトは、  unsafeコード以外からは mutable reference を取得できない  safe関数でラップして通常操作での安全性を担保する  immutable reference の取得は問題なく行える  immutable reference からは move をすることができないため つまり Pin されたオブジェクトは以下のように振る舞えば良い
  • 16. The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)  Pinしていても自由にMoveできる構造体には Unpin (auto-trait) がついている  普通に構造体を作ると Unpin が勝手につくので Move 可能な構造体として振る舞う  get_mut() で mutable reference が取れてしまう  扱う構造体が move に対して安全じゃない場合は構造体に std::marker::PhantomPinned を持たせることで Unpin を opt-out する必要がある struct SelfRef { ary: [i32; 2], ptr: NonNull<i32>, _pin: PhantomPinned } SelfRefはPinされているときにMoveを 安全に行うことが出来ないことを宣言
  • 17. The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)  Box::pin, Rc::pin, Arc::pin でPINされたスマートポインタを作れる impl SelfRef { fn new(ary: [i32; 2]) -> Pin<Box<SelfRef>> { let data = SelfRef { ary, ptr: NonNull::dangling(), _pin: PhantomPinned }; let mut boxed = Box::pin(data); let ptr = NonNull::from(&boxed.ary[0]); unsafe { boxed.as_mut().get_unchecked_mut().ptr = ptr; } boxed } }
  • 18. The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)  unsafe コードを通してデータを変更 impl SelfRef { fn new(ary: [i32; 2]) -> Pin<Box<SelfRef>> { let data = SelfRef { ary, ptr: NonNull::dangling(), _pin: PhantomPinned }; let mut boxed = Box::pin(data); let ptr = NonNull::from(&boxed.ary[0]); unsafe { boxed.as_mut().get_unchecked_mut().ptr = ptr; } boxed } }
  • 19. The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)  unsafe部分を分解して、型を追いかける unsafe { boxed.as_mut().get_unchecked_mut().ptr = ptr; } unsafe { let mut_ref = boxed.as_mut(); let mut_obj = mut_ref.get_unchecked_mut(); mut_obj.ptr = ptr; } 等価な変換 Pin<Box<SelfRef>>を Pin<&mut SelfRef> に変換 &mut SelfRef に変換 (unsafe) &mut SelfRef を変更
  • 20. The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)  get は deref が効くので self をとって処理をすることができる  set は &mut Pin<Box<Self>> が必要なのでselfを使ったメソッド構文が使えない  Pin<Box<Self>>, Arc<Self> などはできるようになってます (v1.33)  arbitrary_self_types を使えばできる (nightly) pub fn get(&self) -> i32 { unsafe { *self.ptr.as_ref() } } pub fn set(target: &mut Pin<Box<Self>>, value: i32) { unsafe { *target.as_mut().get_unchecked_mut().ptr.as_mut() = value; } }
  • 21. The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)  setと同じくPin<Box<Self>>が必要なので、メソッド呼び出し構文は使用不可 pub fn toggle(target: &mut Pin<Box<Self>>) { let ptr; if NonNull::from(&target.ary[0]) == target.ptr { ptr = NonNull::from(&target.ary[1]); } else { ptr = NonNull::from(&target.ary[0]); } unsafe { target.as_mut().get_unchecked_mut().ptr = ptr; } }
  • 22. The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)  SelfRef::set, SelfRef::toggle は通常の関数呼び出しを使う必要がある  struct ToggleInt { inner: Pin<Box<SelfRef>> } のように別構造体で包めば、 使いやすいインターフェースを提供することも可能 let mut data = SelfRef::new([1, 2]); assert_eq!(1, data.get()); SelfRef::set(&mut data, 100); assert_eq!(100, data.get()); SelfRef::toggle(&mut data); assert_eq!(2, data.get()); SelfRef::toggle(&mut data); assert_eq!(100, data.get());
  • 23. The Rust logo is licensed under CC BY 4.0 (This is unofficial slide)  std::pin を使うと move 不可なオブジェクトが作れる  std::pin を使うのに unsafe コードは必須  必要性が薄いなら別実装を考えたほうが良いかも  Pin<Box<T>> を生で扱うとインターフェースが汚くなるので注意  Pin<Box<T>> ならメソッドレシーバーにできるけど、&mut Pin<Box<T>> とかはまだ無 理  キレイなインターフェース版は GitHub においておきます https://github.com/StoneDot/toggle-int

Notas del editor

  1. impl SelfRef { fn new() -> SelfRef { let mut ary = [1, 2]; let mut data = SelfRef { ary, ptr: NonNull::dangling() }; data.ptr = NonNull::from(&ary[0]); data } }