SlideShare une entreprise Scribd logo
1  sur  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

Contenu connexe

Tendances

Scapyで作る・解析するパケット
Scapyで作る・解析するパケットScapyで作る・解析するパケット
Scapyで作る・解析するパケットTakaaki Hoyo
 
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)NTT DATA Technology & Innovation
 
非同期処理の基礎
非同期処理の基礎非同期処理の基礎
非同期処理の基礎信之 岩永
 
CRDT in 15 minutes
CRDT in 15 minutesCRDT in 15 minutes
CRDT in 15 minutesShingo Omura
 
Unified JVM Logging
Unified JVM LoggingUnified JVM Logging
Unified JVM LoggingYuji Kubota
 
Grafana LokiではじめるKubernetesロギングハンズオン(NTT Tech Conference #4 ハンズオン資料)
Grafana LokiではじめるKubernetesロギングハンズオン(NTT Tech Conference #4 ハンズオン資料)Grafana LokiではじめるKubernetesロギングハンズオン(NTT Tech Conference #4 ハンズオン資料)
Grafana LokiではじめるKubernetesロギングハンズオン(NTT Tech Conference #4 ハンズオン資料)NTT DATA Technology & Innovation
 
目grep入門 +解説
目grep入門 +解説目grep入門 +解説
目grep入門 +解説murachue
 
40歳過ぎてもエンジニアでいるためにやっていること
40歳過ぎてもエンジニアでいるためにやっていること40歳過ぎてもエンジニアでいるためにやっていること
40歳過ぎてもエンジニアでいるためにやっていることonozaty
 
BuildKitの概要と最近の機能
BuildKitの概要と最近の機能BuildKitの概要と最近の機能
BuildKitの概要と最近の機能Kohei Tokunaga
 
Pythonとパッケージングと私
Pythonとパッケージングと私Pythonとパッケージングと私
Pythonとパッケージングと私Atsushi Odagiri
 
人生がときめくAPIテスト自動化 with Karate
人生がときめくAPIテスト自動化 with Karate人生がときめくAPIテスト自動化 with Karate
人生がときめくAPIテスト自動化 with KarateTakanori Suzuki
 
キャッシュコヒーレントに囚われない並列カウンタ達
キャッシュコヒーレントに囚われない並列カウンタ達キャッシュコヒーレントに囚われない並列カウンタ達
キャッシュコヒーレントに囚われない並列カウンタ達Kumazaki Hiroki
 
Dockerセキュリティ: 今すぐ役に立つテクニックから,次世代技術まで
 Dockerセキュリティ: 今すぐ役に立つテクニックから,次世代技術まで Dockerセキュリティ: 今すぐ役に立つテクニックから,次世代技術まで
Dockerセキュリティ: 今すぐ役に立つテクニックから,次世代技術までAkihiro Suda
 
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture世界一わかりやすいClean Architecture
世界一わかりやすいClean ArchitectureAtsushi Nakamura
 
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)Kuniyasu Suzaki
 
Pythonはどうやってlen関数で長さを手にいれているの?
Pythonはどうやってlen関数で長さを手にいれているの?Pythonはどうやってlen関数で長さを手にいれているの?
Pythonはどうやってlen関数で長さを手にいれているの?Takayuki Shimizukawa
 

Tendances (20)

Scapyで作る・解析するパケット
Scapyで作る・解析するパケットScapyで作る・解析するパケット
Scapyで作る・解析するパケット
 
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)
 
Docker超入門
Docker超入門Docker超入門
Docker超入門
 
非同期処理の基礎
非同期処理の基礎非同期処理の基礎
非同期処理の基礎
 
CRDT in 15 minutes
CRDT in 15 minutesCRDT in 15 minutes
CRDT in 15 minutes
 
Unified JVM Logging
Unified JVM LoggingUnified JVM Logging
Unified JVM Logging
 
Grafana LokiではじめるKubernetesロギングハンズオン(NTT Tech Conference #4 ハンズオン資料)
Grafana LokiではじめるKubernetesロギングハンズオン(NTT Tech Conference #4 ハンズオン資料)Grafana LokiではじめるKubernetesロギングハンズオン(NTT Tech Conference #4 ハンズオン資料)
Grafana LokiではじめるKubernetesロギングハンズオン(NTT Tech Conference #4 ハンズオン資料)
 
目grep入門 +解説
目grep入門 +解説目grep入門 +解説
目grep入門 +解説
 
Glibc malloc internal
Glibc malloc internalGlibc malloc internal
Glibc malloc internal
 
40歳過ぎてもエンジニアでいるためにやっていること
40歳過ぎてもエンジニアでいるためにやっていること40歳過ぎてもエンジニアでいるためにやっていること
40歳過ぎてもエンジニアでいるためにやっていること
 
BuildKitの概要と最近の機能
BuildKitの概要と最近の機能BuildKitの概要と最近の機能
BuildKitの概要と最近の機能
 
Pythonとパッケージングと私
Pythonとパッケージングと私Pythonとパッケージングと私
Pythonとパッケージングと私
 
人生がときめくAPIテスト自動化 with Karate
人生がときめくAPIテスト自動化 with Karate人生がときめくAPIテスト自動化 with Karate
人生がときめくAPIテスト自動化 with Karate
 
Metaspace
MetaspaceMetaspace
Metaspace
 
キャッシュコヒーレントに囚われない並列カウンタ達
キャッシュコヒーレントに囚われない並列カウンタ達キャッシュコヒーレントに囚われない並列カウンタ達
キャッシュコヒーレントに囚われない並列カウンタ達
 
OAuth 2.0のResource Serverの作り方
OAuth 2.0のResource Serverの作り方OAuth 2.0のResource Serverの作り方
OAuth 2.0のResource Serverの作り方
 
Dockerセキュリティ: 今すぐ役に立つテクニックから,次世代技術まで
 Dockerセキュリティ: 今すぐ役に立つテクニックから,次世代技術まで Dockerセキュリティ: 今すぐ役に立つテクニックから,次世代技術まで
Dockerセキュリティ: 今すぐ役に立つテクニックから,次世代技術まで
 
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
 
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
 
Pythonはどうやってlen関数で長さを手にいれているの?
Pythonはどうやってlen関数で長さを手にいれているの?Pythonはどうやってlen関数で長さを手にいれているの?
Pythonはどうやってlen関数で長さを手にいれているの?
 

Similaire à 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
 

Similaire à 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
 

Dernier

論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Gamesatsushi061452
 
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。iPride Co., Ltd.
 
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルLoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルCRI Japan, Inc.
 
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video UnderstandingToru Tamaki
 
Utilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native IntegrationsUtilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native IntegrationsWSO2
 
新人研修 後半 2024/04/26の勉強会で発表されたものです。
新人研修 後半        2024/04/26の勉強会で発表されたものです。新人研修 後半        2024/04/26の勉強会で発表されたものです。
新人研修 後半 2024/04/26の勉強会で発表されたものです。iPride Co., Ltd.
 
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
LoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイスLoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイス
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイスCRI Japan, Inc.
 
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...Toru Tamaki
 
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。iPride Co., Ltd.
 
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)Hiroshi Tomioka
 
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptxsn679259
 

Dernier (11)

論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
 
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
 
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルLoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
 
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
 
Utilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native IntegrationsUtilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native Integrations
 
新人研修 後半 2024/04/26の勉強会で発表されたものです。
新人研修 後半        2024/04/26の勉強会で発表されたものです。新人研修 後半        2024/04/26の勉強会で発表されたものです。
新人研修 後半 2024/04/26の勉強会で発表されたものです。
 
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
LoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイスLoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイス
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
 
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
 
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
 
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
 
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
 

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

Notes de l'éditeur

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