# 卒研経過報告 #1 Rustによる組み込みプログラミング マイコンWio terminalを用いたRustとC言語の信頼性,安全性の比較検証、考察 team member : 子安,小森 [先週のメモ](https://hackmd.io/lXiKoN4rTE6nx6zoGcDNRg) ## 研究の目的 この研究ではこれまで主に組込みソフトウエア開発に使われてきたC/C++と それに替わる有効な選択肢として、注目されているRust言語との 信頼性や安全性など様々な面から比較検証を行う。 ## memo - メモリ管理 - 静的領域(グローバル変数) - スタック領域(ローカル変数)[](cでは自動変数) - malloc(ヒープ領域) - メモリの二重解放 - rustでは絶対に起こりえない(コンパイラが検出) - 型状態プログラミング - 状態の変化を型で表しコンパイラがチェック - 実行せずともコンパイラがバグを検知できるため安全 - ガベージコレクション 多くの言語ではメモリーリークや,二重解放などのミスによってメモリが占拠されてしまうのを防ぐため**ガベージコレクション**という機能が存在する.しかしC/C++,Rustなどの言語では,ガベージコレクションを採用していない. - ポインタに関連するバグ C/C++では、以下のように誤ったメモリ確保/解放を行うと、プログラムの性能劣化やメモリ不足によるプログラムの機能停止、予期せぬ動作を引き起こすことがある。 - メモリリーク 確保したメモリを解放し忘れることで、プログラムの動作に不要なメモリ領域が占有され続ける実装ミス。 - メモリの二重解放 一度解放したメモリを、再度解放してしまう実装ミス - ダングリングポインタの使用 解放済みのメモリ領域を参照するポインタ(ダングリングポインタ)を使用してしまう実装ミス ## 直近の課題 - malloc等を用いメモリを確保し、cとrustの比較検証 - c言語にはない型状態プログラミングの考察 ## 検証 ### 1. 所有者システム ### c言語のメモリ管理について c言語の主な特徴としてプログラマ個人が、ヒープから領域を確保するmalloc()や解放を行うfree()等の操作を行う必要があるということ。つまり、プログラマーが全ての制御権を持つことにある。 プログラマのミスによってメモリーリーク、二重解放等が発生する. ### c言語の場合(ポインタに関するエラー) * **二重解放** 一度解放したメモリをもう一度解放しようとすること ![](https://i.imgur.com/pyRJtBj.png) 実行はできないが、コンパイルは通る * **メモリリーク** 確保したメモリを解放し忘れること ```c= #include <stdio.h> #include <stdlib.h> #include <memory.h> int main(int argc, char** args){ int i; char *p; for (i = 0; i < 10000;i++){ // メモリを生成(解放しない) p = (char*)malloc(sizeof(char) * 10000); } return 0; } ``` * **ダングリングポインタへのアクセス** 解放済みで無効になったメモリにアクセスすること ```c= char *p = malloc(1); // メモリ確保 free(p); // メモリ解放 // これ以降ポインタ変数`p`はダングリングポインタ p; *p = 'c'; // ダングリングポインタへのアクセス(危険) ``` スコープの外に出てダングリングポインタになったポインタへのアクセスも同様 ```c= char *p = NULL; { // 自動変数`c`の生存期間はスコープ内のみ char c = 'c'; p = &c; // ローカル変数の参照を保持 } // ローカル変数`c`の寿命は既に尽きている p; // よってポインタpはダングリングポインタ printf("%c", *p); // 不定な動作を引き起こすため危険 ``` ### rustの場合 ダングリングポインタへの参照はrustではコンパイル時に検出してくれる。 ``` fn main() { let reference_to_nothing = dangle(); } fn dangle() -> &String { // dangleはStringへの参照を返す let s = String::from("hello"); // sは新しいString &s // String sへの参照を返す }// ここで、sはスコープを抜け、メモリは解放される。 ``` エラー文 ``` error[E0106]: missing lifetime specifier (エラー: ライフタイム指定子がありません) --> main.rs:5:16 | 5 | fn dangle() -> &String { | ^ expected lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from (助言: この関数の戻り値型は、借用した値を含んでいますが、借用される値がどこにもありません) = help: consider giving it a 'static lifetime ('staticライフタイムを与えることを考慮してみてください) ``` sはdangle内で生成されており、dangleを抜けるとsは解放されるが、そこへの参照を返そうとしている。 所有者に対する参照がメモリの生存期間を超えている場合コンパイルエラーになることが分かった。 ### rustの所有権システム Rustにはメモリ管理について所有権,借用権,ライフタイムという独特な仕組みを採用している.所有権の主な規則として以下のルールがある。 * 各値は、所有者と呼ばれる変数と対応している * いかなる時も所有者は一つである * 所有者がスコープから外れたら、値は破棄される この仕組みがプログラマがメモリ管理をコントロールすることが出来る。 * スタック領域に確保される型[](プリミティブ型変数) ```rust= { let x = 1; // x のメモリ領域の確保 } // x のメモリ領域の解放 ``` * ヒープ領域に確保される型[](String型変数) ```rust= fn main() { let a = String::from("Hello"); // ヒープ領域のメモリ確保 let b = a; //ムーブ println!("b = {}", b); // OK println!("a = {}", a); // エラー } ``` [](ムーブヒープ領域の所有権がポインタ変数`a`から`b`へ移った。ヒープ領域の所有は必ず1つのポインタ変数のみ) エラー ``` Compiling playground v0.0.1 (/playground) error[E0382]: borrow of moved value: `a` --> src/main.rs:5:24 | 2 | let a = String::from("Hello"); // ヒープ領域のメモリ確保 | - move occurs because `a` has type `String`, which does not implement the `Copy` trait 3 | let b = a; // ムーブ(ヒープ領域の所有権がポインタ変数`a`から`b`へ移った。ヒープ領域の所有は必ず1つのポインタ変数のみ) ... | - value moved here 4 | println!("b = {}", b); // OK 5 | println!("a = {}", a); // エラー | ^ value borrowed here after move For more information about this error, try `rustc --explain E0382`. error: could not compile `playground` due to previous error ``` rustでは処理の回数を減らすため、参照できるポインタを一つだけにしている。そのため上のようにムーブ後はaの値にアクセスすることはできない。これらの特徴がc言語と大きく異なる部分である。 cとrustでヒープ変数での代入の動きを確認すると、 c言語ではスタック変数で新たにメモリを確保するのに対し、 rustでは代入元を無効にするムーブという動きをすることを確認した。 ## 今後の課題 * 型状態プログラミングの利点を具体例によって確認 ## 参考文献 [1] [公式ドキュメント](https://doc.rust-jp.rs/book-ja/foreword.html) [2] 中林智之著「基礎から学ぶ組み込みRust」シーアンドアール研究所出版 [](https://qiita.com/ksato9700/items/312be99d8264b553b193) [](https://qiita.com/nirasan/items/9e169859c6807c2c175b) [malloc関数(メモリの動的確保)について分かりやすく解説](https://daeudaeu.com/c_malloc/#C) [Rust は何を解決しようとしたのか;メモリとリソースと所有権 ](https://zenn.dev/karno/articles/630a64fbc9c65e29b566) [Rustと所有権](https://www.eidos.ic.i.u-tokyo.ac.jp/~tau/lecture/programming_languages/presentations/2020/kondo-yoshida-rust.pdf) []() https://doc.rust-jp.rs/rust-nomicon-ja/ownership.html https://ytyaru.hatenablog.com/entry/2020/08/16/000000