Unsafeとなった関数
Rust 2024では、いくつかの関数がUnsafeとなりました。
Unsafeとなった関数は以下の通りです。
- std::env::set_var
- std::env::remove_var
- std::os::unix::process::CommandExt::before_exec
本来はunsafeとマークされるべき関数群でしたが、既存のコードの破壊的変更となるのを避けるためにunsafeとマークされていませんでした。それが、Rust 2024では正しくunsafeとマークされるようになりました。
std::env::set_varとstd::env::remove_varは、いずれもOSの環境変数の操作のための関数です。マルチスレッド環境では安全でないとされ、unsafeとマークされるようになりました。Rust 2024においてこれらの関数を含むコードを正しくコンパイルできるようにするには、以下の修正を加えます。
std::env::set_var("ENV_VAR", "HELLO");
↓
unsafe { std::env::set_var("ENV_VAR", "HELLO") };
ただし、コンパイルは通っても、実際に正しく動作する保証はありません。特にマルチスレッド環境では、前述の通り危険であることには変わりないので、あくまでもコンパイルが通るようにするだけの暫定的処置として対策することが必要です。
std::os::unix::process::CommandExt::before_execは、Unixプラットフォーム特有の関数で、execシステムコールを呼び出す前に特定のクロージャを呼び出します。この関数はRust 1.37において非推奨となり、pre_execという同じ目的の関数に置き換えられました。pre_exec関数は登場時からunsafeとマークされています。
今回の変更は、before_exec関数もunsafeとマークされることで、古いコードがこの関数を使っている際に、unsafeブロックを伴うpre_exec関数への移行を進めるためのものと言えます。
Unsafeのマークが必須となった属性
Rust 2024では、いくつかの属性がUnsafeとなりました。
Unsafeとなった属性は以下の通りです。
- export_name
- link_section
- no_mangle
安全でない属性にunsafeでマークする機能は、Rust 1.82で追加されました。これは、属性の使用において安全であることを開発者が意識して示すことを目的としています。Rust 2024では、上記の属性にunsafeでマークすることが必須となりました。
export_name属性は、シンボルをエクスポートする際の名前を以下のリストのように明示します。この場合、foo関数はmallocとしてエクスポートされます。ところが、mallocはC言語の標準ライブラリに存在する名前なので、このプログラムはsegmentation faultとなってクラッシュします。
このように安全でないことを明示すべく、unsafeによるマークが必須となりました。
fn main() { println!("Hello, world!"); } #[unsafe(export_name = "malloc")] // unsafeとマークする fn foo() -> usize { 1 }
link_section属性は、関数や静的変数の置かれるオブジェクトファイル上のセクションを指定します。通常、これらのオブジェクトが置かれるセクションは決められています。この属性を使うと、例えばミュータブルな変数を読み取り専用領域に配置することなどが可能になりますが、予期しないプログラムの動作を招く可能性があるため安全ではありません。
no_mangle属性は既出ですが、続くシンボル定義のマングリングを行わないようにします。これは、マングリングの必要性を否定する属性なので名前の衝突を招く可能性があり、この点から安全ではないとされています。
まとめ
今回は、Unsafe Rustに関わる変更として、Unsafeな関数内におけるUnsafeなコードの扱い、Unsafeとなったexternブロック、Unsafeとなった関数、Unsafeのマークが必須となった属性などについて、Unsafe Rustのあらましとともに紹介しました。
次回は、RustのツールチェインであるパッケージマネージャCargoやコードフォーマッタRustFmtの変更について、Cargoのパッケージ管理機能とRustFmtのコードフォーマット機能のあらましとともに紹介します。