SlideShare a Scribd company logo
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

More Related Content

What's hot

世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
Atsushi Nakamura
 
目grep入門 +解説
目grep入門 +解説目grep入門 +解説
目grep入門 +解説
murachue
 
DockerコンテナでGitを使う
DockerコンテナでGitを使うDockerコンテナでGitを使う
DockerコンテナでGitを使う
Kazuhiro Suga
 
組織にテストを書く文化を根付かせる戦略と戦術
組織にテストを書く文化を根付かせる戦略と戦術組織にテストを書く文化を根付かせる戦略と戦術
組織にテストを書く文化を根付かせる戦略と戦術
Takuto Wada
 
Dockerfileを改善するためのBest Practice 2019年版
Dockerfileを改善するためのBest Practice 2019年版Dockerfileを改善するためのBest Practice 2019年版
Dockerfileを改善するためのBest Practice 2019年版
Masahito Zembutsu
 
TLS, HTTP/2演習
TLS, HTTP/2演習TLS, HTTP/2演習
TLS, HTTP/2演習
shigeki_ohtsu
 
PHP の GC の話
PHP の GC の話PHP の GC の話
PHP の GC の話
y-uti
 
ARM CPUにおけるSIMDを用いた高速計算入門
ARM CPUにおけるSIMDを用いた高速計算入門ARM CPUにおけるSIMDを用いた高速計算入門
ARM CPUにおけるSIMDを用いた高速計算入門
Fixstars Corporation
 
DeClang 誕生!Clang ベースのハッキング対策コンパイラ【DeNA TechCon 2020 ライブ配信】
DeClang 誕生!Clang ベースのハッキング対策コンパイラ【DeNA TechCon 2020 ライブ配信】DeClang 誕生!Clang ベースのハッキング対策コンパイラ【DeNA TechCon 2020 ライブ配信】
DeClang 誕生!Clang ベースのハッキング対策コンパイラ【DeNA TechCon 2020 ライブ配信】
DeNA
 
Dockerfile を書くためのベストプラクティス解説編
Dockerfile を書くためのベストプラクティス解説編Dockerfile を書くためのベストプラクティス解説編
Dockerfile を書くためのベストプラクティス解説編
Masahito Zembutsu
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
Takuto Wada
 
BuildKitの概要と最近の機能
BuildKitの概要と最近の機能BuildKitの概要と最近の機能
BuildKitの概要と最近の機能
Kohei Tokunaga
 
Lockfree Queue
Lockfree QueueLockfree Queue
Lockfree Queue
Kumazaki Hiroki
 
C# 8.0 null許容参照型
C# 8.0 null許容参照型C# 8.0 null許容参照型
C# 8.0 null許容参照型
信之 岩永
 
【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All Things【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All Things
UnityTechnologiesJapan002
 
DockerとPodmanの比較
DockerとPodmanの比較DockerとPodmanの比較
DockerとPodmanの比較
Akihiro Suda
 
ゼロからはじめるKVM超入門
ゼロからはじめるKVM超入門ゼロからはじめるKVM超入門
ゼロからはじめるKVM超入門
VirtualTech Japan Inc.
 
BuildKitによる高速でセキュアなイメージビルド
BuildKitによる高速でセキュアなイメージビルドBuildKitによる高速でセキュアなイメージビルド
BuildKitによる高速でセキュアなイメージビルド
Akihiro Suda
 
Marp Tutorial
Marp TutorialMarp Tutorial
Marp Tutorial
Rui Watanabe
 
ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計
Yoshinori Matsunobu
 

What's hot (20)

世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
 
目grep入門 +解説
目grep入門 +解説目grep入門 +解説
目grep入門 +解説
 
DockerコンテナでGitを使う
DockerコンテナでGitを使うDockerコンテナでGitを使う
DockerコンテナでGitを使う
 
組織にテストを書く文化を根付かせる戦略と戦術
組織にテストを書く文化を根付かせる戦略と戦術組織にテストを書く文化を根付かせる戦略と戦術
組織にテストを書く文化を根付かせる戦略と戦術
 
Dockerfileを改善するためのBest Practice 2019年版
Dockerfileを改善するためのBest Practice 2019年版Dockerfileを改善するためのBest Practice 2019年版
Dockerfileを改善するためのBest Practice 2019年版
 
TLS, HTTP/2演習
TLS, HTTP/2演習TLS, HTTP/2演習
TLS, HTTP/2演習
 
PHP の GC の話
PHP の GC の話PHP の GC の話
PHP の GC の話
 
ARM CPUにおけるSIMDを用いた高速計算入門
ARM CPUにおけるSIMDを用いた高速計算入門ARM CPUにおけるSIMDを用いた高速計算入門
ARM CPUにおけるSIMDを用いた高速計算入門
 
DeClang 誕生!Clang ベースのハッキング対策コンパイラ【DeNA TechCon 2020 ライブ配信】
DeClang 誕生!Clang ベースのハッキング対策コンパイラ【DeNA TechCon 2020 ライブ配信】DeClang 誕生!Clang ベースのハッキング対策コンパイラ【DeNA TechCon 2020 ライブ配信】
DeClang 誕生!Clang ベースのハッキング対策コンパイラ【DeNA TechCon 2020 ライブ配信】
 
Dockerfile を書くためのベストプラクティス解説編
Dockerfile を書くためのベストプラクティス解説編Dockerfile を書くためのベストプラクティス解説編
Dockerfile を書くためのベストプラクティス解説編
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
 
BuildKitの概要と最近の機能
BuildKitの概要と最近の機能BuildKitの概要と最近の機能
BuildKitの概要と最近の機能
 
Lockfree Queue
Lockfree QueueLockfree Queue
Lockfree Queue
 
C# 8.0 null許容参照型
C# 8.0 null許容参照型C# 8.0 null許容参照型
C# 8.0 null許容参照型
 
【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All Things【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All Things
 
DockerとPodmanの比較
DockerとPodmanの比較DockerとPodmanの比較
DockerとPodmanの比較
 
ゼロからはじめるKVM超入門
ゼロからはじめるKVM超入門ゼロからはじめるKVM超入門
ゼロからはじめるKVM超入門
 
BuildKitによる高速でセキュアなイメージビルド
BuildKitによる高速でセキュアなイメージビルドBuildKitによる高速でセキュアなイメージビルド
BuildKitによる高速でセキュアなイメージビルド
 
Marp Tutorial
Marp TutorialMarp Tutorial
Marp Tutorial
 
ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計
 

Similar to std::pin の勘所

katagaitai CTF勉強会 #5 Crypto
katagaitai CTF勉強会 #5 Cryptokatagaitai CTF勉強会 #5 Crypto
katagaitai CTF勉強会 #5 Crypto
trmr
 
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
Naoya Nakazawa
 
インメモリーで超高速処理を実現する場合のカギ
インメモリーで超高速処理を実現する場合のカギインメモリーで超高速処理を実現する場合のカギ
インメモリーで超高速処理を実現する場合のカギ
Masaki Yamakawa
 
LagopusとAzureとIPsecとDPDK
LagopusとAzureとIPsecとDPDKLagopusとAzureとIPsecとDPDK
LagopusとAzureとIPsecとDPDK
Tomoya Hibi
 
フラッター開発におけるシークレット情報取扱考察
フラッター開発におけるシークレット情報取扱考察フラッター開発におけるシークレット情報取扱考察
フラッター開発におけるシークレット情報取扱考察
cch-robo
 
ハードウェアによる仮想化支援機能を利用したハイパバイザーIPS
ハードウェアによる仮想化支援機能を利用したハイパバイザーIPSハードウェアによる仮想化支援機能を利用したハイパバイザーIPS
ハードウェアによる仮想化支援機能を利用したハイパバイザーIPSFFRI, Inc.
 
Kanazawa.js.Next
Kanazawa.js.NextKanazawa.js.Next
Kanazawa.js.Next
dynamis
 
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
 
Aerospike deep dive LDTs
Aerospike deep dive LDTsAerospike deep dive LDTs
Aerospike deep dive LDTs
Masaki Toyoshima
 
Lagopusで試すFirewall
Lagopusで試すFirewallLagopusで試すFirewall
Lagopusで試すFirewall
Tomoya 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*ck
Uehara 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受信設計2013
Kiyoshi Ogawa
 
YAPC Asia 2010 30days Albumの裏側 後日談
YAPC Asia 2010 30days Albumの裏側 後日談YAPC Asia 2010 30days Albumの裏側 後日談
YAPC Asia 2010 30days Albumの裏側 後日談
Kensuke Nagae
 

Similar to 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
 

Recently uploaded

ヒアラブルへの入力を想定したユーザ定義型ジェスチャ調査と IMUセンサによる耳タッチジェスチャの認識
ヒアラブルへの入力を想定したユーザ定義型ジェスチャ調査と IMUセンサによる耳タッチジェスチャの認識ヒアラブルへの入力を想定したユーザ定義型ジェスチャ調査と IMUセンサによる耳タッチジェスチャの認識
ヒアラブルへの入力を想定したユーザ定義型ジェスチャ調査と IMUセンサによる耳タッチジェスチャの認識
sugiuralab
 
協働AIがもたらす業務効率革命 -日本企業が押さえるべきポイント-Collaborative AI Revolutionizing Busines...
協働AIがもたらす業務効率革命 -日本企業が押さえるべきポイント-Collaborative AI Revolutionizing Busines...協働AIがもたらす業務効率革命 -日本企業が押さえるべきポイント-Collaborative AI Revolutionizing Busines...
協働AIがもたらす業務効率革命 -日本企業が押さえるべきポイント-Collaborative AI Revolutionizing Busines...
Osaka University
 
ロジックから状態を分離する技術/設計ナイト2024 by わいとん @ytnobody
ロジックから状態を分離する技術/設計ナイト2024 by わいとん @ytnobodyロジックから状態を分離する技術/設計ナイト2024 by わいとん @ytnobody
ロジックから状態を分離する技術/設計ナイト2024 by わいとん @ytnobody
azuma satoshi
 
【JSAI2024】LLMエージェントの人間との対話における反芻的返答の親近感向上効果_v1.1.pdf
【JSAI2024】LLMエージェントの人間との対話における反芻的返答の親近感向上効果_v1.1.pdf【JSAI2024】LLMエージェントの人間との対話における反芻的返答の親近感向上効果_v1.1.pdf
【JSAI2024】LLMエージェントの人間との対話における反芻的返答の親近感向上効果_v1.1.pdf
ARISE analytics
 
ハイブリッドクラウド研究会_Hyper-VとSystem Center Virtual Machine Manager セッションMM
ハイブリッドクラウド研究会_Hyper-VとSystem Center Virtual Machine Manager セッションMMハイブリッドクラウド研究会_Hyper-VとSystem Center Virtual Machine Manager セッションMM
ハイブリッドクラウド研究会_Hyper-VとSystem Center Virtual Machine Manager セッションMM
osamut
 
Humanoid Virtual Athletics Challenge2024 技術講習会 スライド
Humanoid Virtual Athletics Challenge2024 技術講習会 スライドHumanoid Virtual Athletics Challenge2024 技術講習会 スライド
Humanoid Virtual Athletics Challenge2024 技術講習会 スライド
tazaki1
 
無形価値を守り育てる社会における「デー タ」の責務について - Atlas, Inc.
無形価値を守り育てる社会における「デー タ」の責務について - Atlas, Inc.無形価値を守り育てる社会における「デー タ」の責務について - Atlas, Inc.
無形価値を守り育てる社会における「デー タ」の責務について - Atlas, Inc.
Yuki Miyazaki
 
生成AIがもたらすコンテンツ経済圏の新時代  The New Era of Content Economy Brought by Generative AI
生成AIがもたらすコンテンツ経済圏の新時代  The New Era of Content Economy Brought by Generative AI生成AIがもたらすコンテンツ経済圏の新時代  The New Era of Content Economy Brought by Generative AI
生成AIがもたらすコンテンツ経済圏の新時代  The New Era of Content Economy Brought by Generative AI
Osaka University
 
「進化するアプリ イマ×ミライ ~生成AIアプリへ続く道と新時代のアプリとは~」Interop24Tokyo APPS JAPAN B1-01講演
「進化するアプリ イマ×ミライ ~生成AIアプリへ続く道と新時代のアプリとは~」Interop24Tokyo APPS JAPAN B1-01講演「進化するアプリ イマ×ミライ ~生成AIアプリへ続く道と新時代のアプリとは~」Interop24Tokyo APPS JAPAN B1-01講演
「進化するアプリ イマ×ミライ ~生成AIアプリへ続く道と新時代のアプリとは~」Interop24Tokyo APPS JAPAN B1-01講演
嶋 是一 (Yoshikazu SHIMA)
 

Recently uploaded (9)

ヒアラブルへの入力を想定したユーザ定義型ジェスチャ調査と IMUセンサによる耳タッチジェスチャの認識
ヒアラブルへの入力を想定したユーザ定義型ジェスチャ調査と IMUセンサによる耳タッチジェスチャの認識ヒアラブルへの入力を想定したユーザ定義型ジェスチャ調査と IMUセンサによる耳タッチジェスチャの認識
ヒアラブルへの入力を想定したユーザ定義型ジェスチャ調査と IMUセンサによる耳タッチジェスチャの認識
 
協働AIがもたらす業務効率革命 -日本企業が押さえるべきポイント-Collaborative AI Revolutionizing Busines...
協働AIがもたらす業務効率革命 -日本企業が押さえるべきポイント-Collaborative AI Revolutionizing Busines...協働AIがもたらす業務効率革命 -日本企業が押さえるべきポイント-Collaborative AI Revolutionizing Busines...
協働AIがもたらす業務効率革命 -日本企業が押さえるべきポイント-Collaborative AI Revolutionizing Busines...
 
ロジックから状態を分離する技術/設計ナイト2024 by わいとん @ytnobody
ロジックから状態を分離する技術/設計ナイト2024 by わいとん @ytnobodyロジックから状態を分離する技術/設計ナイト2024 by わいとん @ytnobody
ロジックから状態を分離する技術/設計ナイト2024 by わいとん @ytnobody
 
【JSAI2024】LLMエージェントの人間との対話における反芻的返答の親近感向上効果_v1.1.pdf
【JSAI2024】LLMエージェントの人間との対話における反芻的返答の親近感向上効果_v1.1.pdf【JSAI2024】LLMエージェントの人間との対話における反芻的返答の親近感向上効果_v1.1.pdf
【JSAI2024】LLMエージェントの人間との対話における反芻的返答の親近感向上効果_v1.1.pdf
 
ハイブリッドクラウド研究会_Hyper-VとSystem Center Virtual Machine Manager セッションMM
ハイブリッドクラウド研究会_Hyper-VとSystem Center Virtual Machine Manager セッションMMハイブリッドクラウド研究会_Hyper-VとSystem Center Virtual Machine Manager セッションMM
ハイブリッドクラウド研究会_Hyper-VとSystem Center Virtual Machine Manager セッションMM
 
Humanoid Virtual Athletics Challenge2024 技術講習会 スライド
Humanoid Virtual Athletics Challenge2024 技術講習会 スライドHumanoid Virtual Athletics Challenge2024 技術講習会 スライド
Humanoid Virtual Athletics Challenge2024 技術講習会 スライド
 
無形価値を守り育てる社会における「デー タ」の責務について - Atlas, Inc.
無形価値を守り育てる社会における「デー タ」の責務について - Atlas, Inc.無形価値を守り育てる社会における「デー タ」の責務について - Atlas, Inc.
無形価値を守り育てる社会における「デー タ」の責務について - Atlas, Inc.
 
生成AIがもたらすコンテンツ経済圏の新時代  The New Era of Content Economy Brought by Generative AI
生成AIがもたらすコンテンツ経済圏の新時代  The New Era of Content Economy Brought by Generative AI生成AIがもたらすコンテンツ経済圏の新時代  The New Era of Content Economy Brought by Generative AI
生成AIがもたらすコンテンツ経済圏の新時代  The New Era of Content Economy Brought by Generative AI
 
「進化するアプリ イマ×ミライ ~生成AIアプリへ続く道と新時代のアプリとは~」Interop24Tokyo APPS JAPAN B1-01講演
「進化するアプリ イマ×ミライ ~生成AIアプリへ続く道と新時代のアプリとは~」Interop24Tokyo APPS JAPAN B1-01講演「進化するアプリ イマ×ミライ ~生成AIアプリへ続く道と新時代のアプリとは~」Interop24Tokyo APPS JAPAN B1-01講演
「進化するアプリ イマ×ミライ ~生成AIアプリへ続く道と新時代のアプリとは~」Interop24Tokyo APPS JAPAN B1-01講演
 

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

Editor's Notes

  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 } }