SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Rustの新機能を探る

Rust 2024におけるUnsafe Rustのさまざまな変更を理解する

Rustの新機能を探る 第2回

  • X ポスト
  • このエントリーをはてなブックマークに追加

Unsafe Rustとは

 Rustは、メモリ安全を特徴とするプログラミング言語です。

 メモリの確保や破棄、メモリ領域の利用について厳格なルールが課され、安全でないコードはコンパイル時に指摘されエラーとすることで、ルールに沿ったコーディングを強制されます。窮屈さは否めませんが、見返りとしてメモリに起因する不具合を最小限に抑えたコーディングが可能です。

 しかしながら、この制約の中では実現できないことが、特にシステムプログラミングのカテゴリには多数存在します。

 システムプログラミングは、微妙なメモリ操作やI/O操作、OSとの連携など、低レベルの処理を要求されることが多いため、必然的にこれらを可能にするプログラミング言語が使われてきました。その代表が、C/C++です。

 Rustには、こういった用途に対応するためのUnsafe Rustがあります。Unsafe Rustの世界では、通常のRustのようなメモリ安全を保証する機構は強制されません。それに加えて、以下の操作が可能になります。

  • 生ポインタの参照外し
  • Unsafeな関数やメソッドの呼び出し
  • ミュータブルな静的変数へのアクセスや変更
  • Unsafeなトレイトの実装

 Unsafe Rustのコードは、以下のように関数定義を含めたunsafeブロックの中に記述します。unsafeブロックの中にだけ安全でないコードを記述し、その他の部分では通常のRustのコードを記述することで、安全でない可能性のある部分を限定できます。

 もちろん、unsafeブロックの外では、Rustのチェック機能が通常通り働きます。

fn main() {
  unsafe {	// Unsafeなブロック
    ...Unsafeなコード...
  }
}

unsafe fn func() {	// Unsafeな関数
}

 以降、Rust 2024におけるUnsafe周りの変更を見ていきます。

Unsafeな関数内におけるUnsafeなコードの扱い

 Rust 2024では、unsafe_op_in_unsafe_fnリントが既定となり、Unsafeな関数内でのUnsafeな操作に警告が発生するようになりました。

 従来は、unsafeとマークされている関数内であれば、Unsafeなコードを特にブロックで囲む必要はありませんでした。Rust 2024では、たとえUnsafeな関数内でも、Unsafeなコードには明示的なマークが必要となりました。

 これに沿わない以下のようなコードでは、unsafe_op_in_unsafe_fnリントにより警告が発生します。get_uncheckedメソッドは、スライスの有効範囲をチェックしないUnsafeな関数であるためです。

リスト unsafe-func/src/main.rs
unsafe fn get_unchecked<T>(x: &[T], i: usize) -> &T {
  x.get_unchecked(i)	// warning: call to unsafe function
}

 この警告を回避するには、関数内でのget_uncheckedメソッドの呼び出しを、以下のようにunsafeブロックで明示的に囲むか、unsafe_op_in_unsafe_fnリントを無効化します。

リスト unsafe-func/src/main.rs
unsafe fn get_unchecked<T>(x: &[T], i: usize) -> &T {
  unsafe {
    x.get_unchecked(i)
  }
}

 この変更の目的は、Unsafeな関数内で安全でないコードが不用意に記述されてしまうのを防ぐことです。

 関数に付与するunsafeキーワードは、その関数の呼び出しにUnsafeなコンテキストが必要であることを示し、その内部で安全でないコードの記述を許可するためものです。後者については、unsafeキーワードの効力に対するリスクが大きいと判断されて、今回の変更に至ったようです。

Unsafeとなったexternブロック

 Rust 2024では、externブロックにunsafeキーワードが必須となりました。

 ここで言うexternブロックとは、他言語の関数に対するインタフェース(FFI; Foreign Function Interface)のためのブロックです。C++言語におけるextern宣言と同様に、主にC言語の関数に対して使います。

[NOTE]extern crate

 externキーワードには、外部クレートを参照するためのextern crateとしての使い方もあります。ただし、Rust 2018でextern crateは不要になり、modキーワードによるモジュール宣言だけで外部クレートのモジュール参照が可能になりました。

 externキーワードは、以下のリストのように使われます。キーワードに続く"C"は、C言語のためのインタフェースであることを示しています。

#[link(name = "ext_lib")]	(1)
extern "C" {
  fn ext_c_func(x: i32) -> i32;	(2)
}

 (1)のlink属性は、外部ライブラリext_lib(Unix系OSではext_lib.so、Windowsではext_lib.dll)の指定、(2)がライブラリ内の関数のシグネチャです。この場合、C言語側では「int _cdecl ext_c_func(int x);」のように関数が宣言されています。

 また、externキーワードは、以下のリストのようにRustの関数をC言語などから利用できるようにするためにも使われます。

#[no_mangle]	(1)
pub extern "C" fn ext_rust_func(x: i32) -> i32 {	(2)
  x % 2
}

 (1)のno_mangle属性は、エクスポートするシンボル名にマングリングを適用しないようにするものです。基本的には宣言した名前がそのままエクスポートされるので、C言語などからその名前を探すことは容易です。

 (2)がエクスポートする関数の定義であり、pubキーワードにより公開可能にするほか、extern "C"キーワードに続けて関数をいつも通りに定義します。

[NOTE]マングリング

 マングリングとは名前修飾ともいい、C++やRustといったコンパイラ型プログラミング言語で名前の衝突を避けるための仕組みです。これらの言語では、名前空間のサポートで同一名称のシンボルを使えますが、これらのサポートのないコンパイラやリンカ、デバッガがこれらのシンボルを識別できるように、グローバルに一意になるように名前を修飾(マングル)します。

 前置きが長くなりましたが、Rust 2024で導入されたexternキーワードに対するunsafeマークは、前者の用法に対するものです。外部で(主にC言語で)作成された関数は、安全である保証はありません。このため、unsafeでマークすることで、externブロック内の関数のシグネチャが正しいものなのか、注意を促します。

 前者のリストは、以下のようになります。加えて、個々のシグネチャにsafe、unsafeをマークできるようになり、Unsafeなブロック内でも安全な関数を明示する、といった指定が可能になっています。

#[link(name = "ext_lib")]
unsafe extern "C" {
  fn ext_c_func(x: i32) -> i32;
  unsafe fn strlen(p: *const std::ffi::c_char) -> usize;
  safe fn sqrt(x: f64) -> f64;
}

 この変更によって、externブロックの利用において、安全に注意しなければならないことがより明確になったと言えます。

次のページ
Unsafeとなった関数

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
Rustの新機能を探る連載記事一覧
この記事の著者

WINGSプロジェクト 山内 直(WINGSプロジェクト ヤマウチ ナオ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook <個人紹介>WINGSプロジェクト所属のテクニカルライター。出版社を経てフリーランスとして独立。ライター、エディター、デベロッパー、講師業に従事。屋号は「たまデジ。」。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/21336 2025/04/16 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング