diff --git a/1.9/ja/book/unsafe.md b/1.9/ja/book/unsafe.md index 3cc5a640..55e8f1ca 100644 --- a/1.9/ja/book/unsafe.md +++ b/1.9/ja/book/unsafe.md @@ -1,13 +1,11 @@ % Unsafe - + + + + + + Rustの主たる魅力は、プログラムの動作についての強力で静的な保証です。 しかしながら、安全性検査は本来保守的なものです。 すなわち、実際には安全なのに、そのことがコンパイラには検証できないプログラムがいくらか存在します。 @@ -15,10 +13,8 @@ Rustの主たる魅力は、プログラムの動作についての強力で静 そのために、Rustには `unsafe` というキーワードがあります。 `unsafe` を使ったコードは、普通のコードよりも制約が少なくなります。 - + + まずシンタックスをみて、それからセマンティクスについて話しましょう。 `unsafe` は4つの場面で使われます。 1つめは、関数がアンセーフであることを印付ける場合です。 @@ -30,10 +26,8 @@ unsafe fn danger_will_robinson() { } ``` - + + たとえば、[FFI][ffi]から呼び出されるすべての関数は`unsafe`で印付けることが必要です。 `unsafe`の2つめの用途は、アンセーフブロックです。 @@ -46,14 +40,14 @@ unsafe { } ``` - + 3つめは、アンセーフトレイトです。 ```rust unsafe trait Scary { } ``` - + そして、4つめは、そのアンセーフトレイトを実装する場合です。 ```rust @@ -61,22 +55,18 @@ unsafe trait Scary { } unsafe impl Scary for i32 {} ``` - + + + 大きな問題を引き起こすバグがあるかもしれないコードを明示できるのは重要なことです。 もしRustのプログラムがセグメンテーション違反を起こしても、バグは `unsafe` で印付けられた区間のどこかにあると確信できます。 + # 「安全」とはどういう意味か? - - + + + Rustの文脈で、安全とは「どのようなアンセーフなこともしない」ことを意味します。 > 訳注: @@ -86,71 +76,65 @@ Rustの文脈で、安全とは「どのようなアンセーフなこともし 知っておくべき重要なことに、たいていのコードにおいて望ましくないが、アンセーフ _ではない_ とされている動作がいくらか存在するということがあります。 - + + + + * デッドロック * メモリやその他のリソースのリーク * デストラクタを呼び出さないプログラム終了 * 整数オーバーフロー - + + + Rustはソフトウェアが抱えるすべての種類の問題を防げるわけではありません。 Rustでバグのあるコードを書くことはできますし、実際に書かれるでしょう。 これらの動作は良いことではありませんが、特にアンセーフだとは見なされません。 - + + さらに、Rustにおいては、次のものは未定義動作で、 `unsafe` コード中であっても、避ける必要があります。 > 訳注: -関数に付いている`unsafe`は「その関数の処理はアンセーフである」ということを表します。 -その一方で、ブロックに付いている`unsafe`は「ブロック中の個々の操作はアンセーフだが、全体としては安全な処理である」ということを表します。 -避ける必要があるのは、未定義動作が起こりうる処理をアンセーフブロックの中に書くことです。 -それは、アンセーフブロックの処理が安全であるために、その内部で未定義動作が決して起こらないことが必要だからです。 -アンセーフ関数には安全性の保証が要らないので、未定義動作が起こりうるアンセーフ関数を定義することに問題はありません。 - - +> 関数に付いている`unsafe`は「その関数の処理はアンセーフである」ということを表します。 +> その一方で、ブロックに付いている`unsafe`は「ブロック中の個々の操作はアンセーフだが、全体としては安全な処理である」ということを表します。 +> 避ける必要があるのは、未定義動作が起こりうる処理をアンセーフブロックの中に書くことです。 +> それは、アンセーフブロックの処理が安全であるために、その内部で未定義動作が決して起こらないことが必要だからです。 +> アンセーフ関数には安全性の保証が要らないので、未定義動作が起こりうるアンセーフ関数を定義することに問題はありません。 + + + + + + + + + + + + + + + + + + + + + + + * データ競合 * ヌル・ダングリング生ポインタの参照外し * [undef][undef] (未初期化)メモリの読み出し * 生ポインタによる [pointer aliasing rules][aliasing] の違反 -* `&mut T` と `&T` は、 `UnsafeCell` を含む `&T` を除き、LLVMのスコープ化された [noalias][noalias] モデルに従っています。アンセーフコードは、それら参照のエイリアシング保証を破ってはいけません。 +* `&mut T` と `&T` は、 `UnsafeCell` を含む `&T` を除き、LLVMのスコープ化された [noalias][noalias] モデルに従っています。 + アンセーフコードは、それら参照のエイリアシング保証を破ってはいけません。 * `UnsafeCell` を持たないイミュータブルな値・参照の変更 * コンパイラIntrinsic経由の未定義挙動の呼び出し - * `std::ptr::offset` (`offset` intrinsic) を使って、オブジェクトの範囲外を指すこと。ただし、オブジェクトの最後より1バイト後を指すことは許されている。 + * `std::ptr::offset` (`offset` intrinsic) を使って、オブジェクトの範囲外を指すこと。 + ただし、オブジェクトの最後より1バイト後を指すことは許されている。 * 範囲の重なったバッファに対して `std::ptr::copy_nonoverlapping_memory` (`memcpy32`/`memcpy64` intrinsics) を使う * プリミティブ型の不正な値(プライベートなフィールドやローカル変数を含む) @@ -165,100 +149,82 @@ avoided, even when writing `unsafe` code: [undef]: http://llvm.org/docs/LangRef.html#undefined-values [aliasing]: http://llvm.org/docs/LangRef.html#pointer-aliasing-rules + # アンセーフの能力 - - - -アンセーフ関数・アンセーフブロックでは、Rustは普段できない3つのことをさせてくれます。たった3つです。それは、 - - + + + +アンセーフ関数・アンセーフブロックでは、Rustは普段できない3つのことをさせてくれます。 +たった3つです。それは、 + + + + 1. [静的ミュータブル変数][static]のアクセスとアップデート。 2. 生ポインタの参照外し。 3. アンセーフ関数の呼び出し。これが最も強力な能力です。 - + + + + 以上です。 重要なのは、 `unsafe` が、たとえば「借用チェッカをオフにする」といったことを行わないことです。 Rustのコードの適当な位置に `unsafe` を加えてもセマンティクスは変わらず、何でもただ受理するようになるということにはなりません。 それでも、`unsafe` はルールのいくつかを破るコードを書けるようにはするのです。 - + + + また、`unsafe` キーワードは、Rust以外の言語とのインターフェースを書くときに遭遇するでしょう。 ライブラリの提供するメソッドの周りに、安全な、Rustネイティブのインターフェースを書くことが推奨されています。 - + これから、その基本的な3つの能力を順番に見ていきましょう。 + ## `static mut` のアクセスとアップデート。 - - + + + Rustには「`static mut`」という、ミュータブルでグローバルな状態を実現する機能があります。 これを使うことはデータレースが起こるおそれがあるので、本質的に安全ではありません。 詳細は、この本の[static][static]セクションを参照してください。 [static]: const-and-static.html#static + ## 生ポインタの参照外し - - - + + + + + 生ポインタによって任意のポインタ演算が可能になりますが、いくつもの異なるメモリ安全とセキュリティの問題が起こるおそれがあります。 ある意味で、任意のポインタを参照外しする能力は行いうる操作のうち最も危険なもののひとつです。 詳細は、[この本の生ポインタに関するセクション][rawpointers]を参照してください。 [rawpointers]: raw-pointers.html + ## アンセーフ関数の呼び出し - - + + この最後の能力は、`unsafe`の両面とともに働きます。 すなわち、`unsafe`で印付けられた関数は、アンセーフブロックの内部からのみ呼び出すことができます。 - + + + この能力は強力で多彩です。 Rustはいくらかの[compiler intrinsics][intrinsics]をアンセーフ関数として公開しており、また、いくつかのアンセーフ関数は安全性検査を回避することで、安全性とスピードを引き換えています。 - -繰り返しになりますが、アンセーフブロックと関数の内部で任意のことが _できる_ としても、それをすべきだということを意味しません。コンパイラは、あなたが不変量を守っているかのように動作しますから、注意してください! + + + +繰り返しになりますが、アンセーフブロックと関数の内部で任意のことが _できる_ としても、それをすべきだということを意味しません。 +コンパイラは、あなたが不変量を守っているかのように動作しますから、注意してください! [intrinsics]: intrinsics.html