diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 6d03c91..6ebb48d 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -117,9 +117,9 @@ - [`if let` temporary scope](rust-2024/temporary-if-let-scope.md) - [Tail expression temporary scope](rust-2024/temporary-tail-expr-scope.md) - [Match ergonomics reservations](rust-2024/match-ergonomics.md) - - [Unsafe `extern` blocks](rust-2024/unsafe-extern.md) - - [Unsafe attributes](rust-2024/unsafe-attributes.md) - - [`unsafe_op_in_unsafe_fn` warning](rust-2024/unsafe-op-in-unsafe-fn.md) + - [アンセーフな `extern` ブロック](rust-2024/unsafe-extern.md) + - [アンセーフなアトリビュート](rust-2024/unsafe-attributes.md) + - [`unsafe_op_in_unsafe_fn` 警告](rust-2024/unsafe-op-in-unsafe-fn.md) - [Disallow references to `static mut`](rust-2024/static-mut-references.md) - [Never type fallback change](rust-2024/never-type-fallback.md) - [Macro fragment specifiers](rust-2024/macro-fragment-specifiers.md) diff --git a/src/rust-2024/unsafe-attributes.md b/src/rust-2024/unsafe-attributes.md index c4a2f13..b9cc761 100644 --- a/src/rust-2024/unsafe-attributes.md +++ b/src/rust-2024/unsafe-attributes.md @@ -1,41 +1,103 @@ -> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページはある時点での英語版をコピーしていますが、一部のリンクが動作しない場合や、最新情報が更新されていない場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** - + + +# アンセーフなアトリビュート + + +## 概要 + +- 以下のアトリビュートに `unsafe` が必要になりました。 - [`export_name`] - [`link_section`] - [`no_mangle`] + +[`export_name`]: https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute +[`link_section`]: https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute +[`no_mangle`]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute + + + +## 詳細 + +Rust 1.82 から全エディションにおいて、アトリビュートが健全性要件の遵守を要する場合に `unsafe` と書ける機能が追加されました。[^RFC3325] +アンセーフなアトリビュートは以下のように使用します。 + + + +```rust +// SAFETY: 同名のグローバル関数は他に存在しない +#[unsafe(no_mangle)] +pub fn example() {} +``` + + +アトリビュートが `unsafe` だと宣言することで、遵守されるべき安全性要件があって、それをコンパイラが保証できないことが明示できます。 + +2024 エディションからは、上記のアトリビュートを `unsafe` とすることが必須となります。 +実際に遵守すべき安全性要件を以下に説明します。 + + + +[^RFC3325]: 元の提案は [RFC 3325](https://rust-lang.github.io/rfcs/3325-unsafe-attributes.html) を参照のこと。 + +### 安全性要件 + + + +アトリビュート [`no_mangle`]、[`export_name`]、[`link_section`] はシンボル名とリンク動作に関わるため、細心の注意を払って使用しなくてはなりません。 + +リンクされるシンボルの名前空間は全ライブラリで共有なので、ライブラリ間でシンボル名が衝突すると問題が発生する可能性があります。 +通常の方法で定義された関数は、[シンボルのマングリング]のおかげで基本的に名前の衝突を気にする必要はありませんが、`export_name` といったアトリビュートを使うとそうはいかなくなります。 + + + +例えば、以下のコードは何もアンセーフと書いていませんが、過去のエディションでは Unix 系の環境でクラッシュします。 ```rust,no_run,edition2021 fn main() { @@ -46,8 +108,13 @@ fn main() { fn foo() -> usize { 1 } ``` + +2024 エディションでは、上記のアトリビュートには `unsafe` をつける必要があり、シンボルが適切に定義される必要があることが明確になります。 + + +```rust,edition2024 +// SAFETY: loop というシンボルの定義は以下のみ +#[unsafe(export_name="loop")] +fn arduino_loop() { + // ... +} +``` + + + +[シンボルのマングリング]: https://doc.rust-lang.org/rustc/symbol-mangling/index.html +[`unsafe_attr_outside_unsafe`]: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#unsafe-attr-outside-unsafe + +## 移行 + + + +[`unsafe_attr_outside_unsafe`] リントで、上記のアトリビュートに `unsafe(...)` を自動付与できます。 +このリントは、自動エディション移行に含まれる `rust-2024-compatibility` リントグループの一部です。 +コードを Rust 2024 互換に移行するには、以下を実行します。 ```sh cargo fix --edition ``` + +ただし、自動移行ツールはアトリビュートの使用方法が正しいことを検証するわけではありません。 +それを保証するのは、変わらずプログラマの責任です。 + + + +変更の必要のあるアトリビュートを検出するリントを手動で有効化することもできます。 + + +```rust +// クレートのトップレベルに以下を追加すると手動移行できる +#![warn(unsafe_attr_outside_unsafe)] +``` diff --git a/src/rust-2024/unsafe-extern.md b/src/rust-2024/unsafe-extern.md index e7af244..87f81ac 100644 --- a/src/rust-2024/unsafe-extern.md +++ b/src/rust-2024/unsafe-extern.md @@ -1,19 +1,48 @@ -> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページはある時点での英語版をコピーしていますが、一部のリンクが動作しない場合や、最新情報が更新されていない場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** - + + +# アンセーフな `extern` ブロック + +## 概要 + + + +- [`extern` ブロック]は `unsafe` として宣言される必要があります。 + +[`extern` ブロック]: https://doc.rust-lang.org/reference/items/external-blocks.html + + + +## 詳細 + +Rust 1.82 から、全エディションで [`extern` ブロック]を `unsafe` キーワードとともに宣言できるようになりました。[^RFC3484] +`unsafe` と書くことで、`extern` を書いた人にシグネチャが正しいことを保証する責任があることが明確になります。 +シグネチャが正しくないと、未定義動作を引き起こしかねません。 + + + +以下に、アンセーフな `extern` ブロック構文の例を示します。 + + +```rust +unsafe extern "C" { + // (libm の) sqrt 関数は任意の `f64` 引数を取れる + pub safe fn sqrt(x: f64) -> f64; + + // (libc の) strlen 関数は有効なポインタを要求するため、 + // アンセーフな関数として宣言する + pub unsafe fn strlen(p: *const std::ffi::c_char) -> usize; + + // safe も unsafe もない関数はデフォルトではアンセーフとなる + pub fn free(p: *mut core::ffi::c_void); + + pub safe static IMPORTANT_BYTES: [u8; 256]; +} +``` + +`extern` ブロックを `unsafe` とできるのに加え、`extern` ブロック内の個々のアイテムを `safe` か `unsafe` と明示できます。 +`safe` のついたアイテムは、`unsafe` で囲まなくても使用できるようになります。 + + + +2024 エディション以降、`extern` ブロックには必ず `unsafe` を付与する必要があります。 +これにより、extern 定義が遵守すべき安全性要件が存在するということが明確になることが期待されます。 + +[^RFC3484]: 元の提案については [RFC 3484](https://github.com/rust-lang/rfcs/blob/master/text/3484-unsafe-extern-blocks.md) を参照のこと。 + + + +## 移行 + + +[`missing_unsafe_on_extern`] リントで `extern` ブロックに `unsafe` を自動付与できます。 +このリントは、自動エディション移行に含まれる `rust-2024-compatibility` リントグループの一部です。 +コードを Rust 2024 互換に移行するには、以下を実行します。 ```sh cargo fix --edition ``` + + +ただし、自動移行ツールは、`extern` ブロックのシグネチャが正しいことを検証することはできません。 +それを保証するのは、変わらずプログラマの責任です。 + +変更の必要がある `unsafe` ブロックを検出するリントを手動で有効化することもできます。 + + + +```rust +// クレートのトップレベルに以下を追加すると手動移行できる +#![warn(missing_unsafe_on_extern)] +``` + + +[`missing_unsafe_on_extern`]: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#missing-unsafe-on-extern diff --git a/src/rust-2024/unsafe-op-in-unsafe-fn.md b/src/rust-2024/unsafe-op-in-unsafe-fn.md index 1cc7ad1..629490c 100644 --- a/src/rust-2024/unsafe-op-in-unsafe-fn.md +++ b/src/rust-2024/unsafe-op-in-unsafe-fn.md @@ -1,26 +1,54 @@ -> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページはある時点での英語版をコピーしていますが、一部のリンクが動作しない場合や、最新情報が更新されていない場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** - + + +# unsafe_op_in_unsafe_fn 警告 + + +## 概要 + +- [`unsafe_op_in_unsafe_fn`] リントのデフォルトのレベルが警告になりました。 + アンセーフな関数中でアンセーフな操作を明示的な unsafe ブロックなしに呼び出した場合にこの警告が出ます。 + + + +[`unsafe_op_in_unsafe_fn`]: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#unsafe-op-in-unsafe-fn + +## 詳細 + + + +[`unsafe_op_in_unsafe_fn`] は、アンセーフな関数中に[アンセーフな操作]が行われているが、それが [`unsafe {}` ブロック][unsafe-block]で囲まれていないことを検出するリントです。 ```rust # #![warn(unsafe_op_in_unsafe_fn)] unsafe fn get_unchecked(x: &[T], i: usize) -> &T { x.get_unchecked(i) // WARNING: requires unsafe block + // (訳) 警告: unsafe ブロックが必要 } ``` + + +これに対処するには、アンセーフな操作をすべて `unsafe` ブロックで囲ってください。 ```rust # #![deny(unsafe_op_in_unsafe_fn)] @@ -29,30 +57,67 @@ unsafe fn get_unchecked(x: &[T], i: usize) -> &T { } ``` + +これは、アンセーフ関数内の意図しないアンセーフな操作を避けるためのものです。 +かつては、アンセーフ関数の `unsafe` というキーワードには二重の意味が込められていました。 +関数を**呼び出す**操作がアンセーフであり、呼び出し側が満たすべき安全性要件が存在するという点と、関数内でアンセーフな操作ができるという点です。 +特に後者を `unsafe` ブロックなしで実行できることが危険すぎると判断されました。 + + + +詳細情報や動機などは [RFC #2585] に詳しいです。 + +[アンセーフな操作]: https://doc.rust-lang.org/reference/unsafety.html +[unsafe-block]: https://doc.rust-lang.org/reference/expressions/block-expr.html#unsafe-blocks +[RFC #2585]: https://rust-lang.github.io/rfcs/2585-unsafe-block-in-unsafe-fn.html + + + +## 移行 + + +[`unsafe_op_in_unsafe_fn`] リントは `rust-2024-compatibility` リントグループの一部です。 +以下を実行すると、コードを Rust 2024 互換に変換できます。 ```sh cargo fix --edition ``` + + +あるいは、unsafe ブロックを追加すべき場所を見つけるために以下のように手動でリントを有効化したり、逆に `allow` としてリントを完全に無視することもできます。 + + +```rust +// クレートのトップレベルに以下を追加すると手動移行できる +#![warn(unsafe_op_in_unsafe_fn)] +```