🔖

バグ報告ではじめるRustコントリビューション

2021/12/13に公開

これは Rust Advent Calendar 2021 13日目の記事です。

以下のバージョンの rustc に基づいています。

rustc 1.41.0 (5e1a79984 2020-01-27)

要約

  • Rust コンパイラのバグを見つけたら気軽に Issue をたててみよう!
  • 英語ができなくても、テンプレートに沿ってコードとエラーメッセージが貼れれば OK!

はじめに

Rust で遊んでいたらこのようなコードでコンパイラがクラッシュする (Internal Compiler Error: ICE) ことに気づきました

use std::time::{Duration, Instant};
use tokio::runtime::Runtime;

async fn foo() {
    
}
fn main() {
    let mut rt = Runtime::new().unwrap();
    let mut sum = Duration::new(0, 0);
    let iteration = 10000;
    
    for _ in 0..iteration {
        sum += rt.block_on(async {
            let start = Instant::now();
    	    foo().await;
    	    start.elapsed()
        });
    }
    println!("duration: {}", sum.as_micros() as f64 / iteration as f64);
}

foo の実行時間を計測するコードです。ところが、このコードは以下のようなエラーを吐き出します。

error: internal compiler error: src/librustc/middle/region.rs:1037: Encountered greater count 28 at span src/main.rs:13:31: 13:46 - expected no greater than 12

thread 'rustc' panicked at 'Box<Any>', src/librustc_errors/lib.rs:905:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.

note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports

note: rustc 1.41.0 (5e1a79984 2020-01-27) running on x86_64-unknown-linux-gnu

note: compiler flags: -C debuginfo=2 -C incremental --crate-type bin

note: some of the compiler flags provided by cargo are hidden

error: aborting due to previous error

調べてみると beta だけではなく stable バージョンでも同じエラーが出ることがわかったので、せっかくなので Issue 報告してみることにしました

はじめての Issue 報告

Issue 立ててみた

当時のコードはかなりの外部ライブラリに依存していたので、なるべく簡潔なコードになるように工夫しました。とりあえず以下のコードで ICE が再現することがわかったので、この内容で Issue を立ててみることにしました。

use tokio::prelude::*;
use tokio::runtime::Runtime;
use tokio::sync::mpsc;

fn main() {
    let mut rt = Runtime::new().unwrap();
    let mut sum = 0;
    sum += rt.block_on(async {
        let (tx, mut rx) = mpsc::unbounded_channel();
        tx.send(1).unwrap();

        while let Some(res) = rx.recv().await {
            println!("{:?}", res);
        }
        1
    });
}

Issue を立てるのは簡単です。New Issue するとどのテンプレートを使うか聞かれるので、

今回は Internal Compiler Error を選択します。このようなテンプレートができるので、必要事項を埋めていくだけで OK です。

できるだけコードを小さくすること、実行時に使った rustc のバージョンを明記することに気をつけるといいでしょう。

If you're using the stable version of the compiler, you should also check if the
bug also exists in the beta or nightly versions.

とあったので、 beta や nightly でも同様なエラーが出ることを確認しました。

というわけで Issue を立てることができました。 Issue のタイトルはどうすればいいかわからなかったので、エラーメッセージから適当につけておきました。

https://github.com/rust-lang/rust/issues/69307

その後の流れ

6 時間後

T-compiler triage: P-high. Leaving nomination label in place, since I don't want to disrupt WG-async-await workflow.
https://github.com/rust-lang/rust/issues/69307#issuecomment-589017751

というコメントがつきました。 Stable でもバグらせているので優先度高めで取り組んでくれるらしいです。うれしい

9 時間後

Rust のコードをいじっていたら最初に提出したコードよりも小さいコードで同様の ICE を起こせることに気づいたので、報告しました。

use tokio::runtime::Runtime;

fn main() {
    let mut rt = Runtime::new().unwrap();
    let mut sum = 0;
    sum += rt.block_on(async {
        (async { }).await;
        1
    });
}

同時に、以下のようでは ICE が起きないことも報告しました

use tokio::runtime::Runtime;

fn main() {
    let mut rt = Runtime::new().unwrap();
    let mut sum = 0;
    sum = sum + rt.block_on(async {
        (async { }).await;
        1
    });
}

結論からいうと、今回のバグは += の右側に async/await を書くとエラーが起きるというものでした。そのためこのコードはデバッグの助けになっていそうでした。 👍 がついてうれしい

22 時間後

外部ライブラリに依存しない minimum なコードの提案がありました。block_on の書き方は自分では絶対気づけないやつですね...。こんな書き方できるんですね。

fn block_on<F>(_: F) -> usize {
    0
}

fn main() {
    let mut sum = 0;
    sum += block_on(async {
        (async {}).await;
        1
    });
}

https://github.com/rust-lang/rust/issues/69307#issuecomment-589497295

35 日後

バグの原因の解析がされました
https://github.com/rust-lang/rust/issues/69307#issuecomment-603448615

また、 PR が作成されました
https://github.com/rust-lang/rust/pull/70367

49 日後

PR が merge されました 🎉

50 日後

rust-lang/glacier に収録されました。
https://github.com/rust-lang/glacier/pull/326

このリポジトリは ICE を引き起こす Rust コードをあつめているようです。 Ice がたくさんあつまって氷河 (Glacier) になってしまったみたいです。

rustc 開発に参加しよう

今回は Issue を立てただけでしたが、自分で Issue を解決できる PR が作成できるようになるとかっこいいですよね。 rustc 開発に加わるのはかなり敷居が高そうなのですが、とっかかりによさそうな動画を見つけたので共有します

https://www.youtube.com/watch?v=9H9SO2u6Q20

ラベルをみて Issue を絞ろう

初心者に有用なラベルが 3 つ紹介されていました。

E-mentor: メンターがついているラベルです。 Issue に取り組むなかで困ったときにメンターに相談できるそうです。
E-easy: コードの修正範囲が小さく、比較的簡単に解決できる Issue です。
P-low: 重要度・緊急度が低い Issue です。時間をかけてゆっくり取り組むことができます。

リソース

まとめ

Rust コンパイラがクラッシュすることに気づいたので Issue を立ててみました。思ったより早く解決されてびっくりしました。
みなさんも Rust コンパイラにバグを見つけたら、気軽に Issue を立ててみましょう。

Discussion