LoginSignup
162
46

More than 3 years have passed since last update.

Let's encryptのバグはRustで実装していたら防げたの?

Last updated at Posted at 2020-03-09

はじめに

Let's encryptのバグの原因はポインタに起因する実装ミスでした。
「Rustはいいぞ」と言うためだけにRustで実装した場合を検証してみます。

原因はなんだった?

詳しくは
https://jovi0608.hatenablog.com/entry/2020/03/09/094737
のステキなまとめを見たほうがいいのですが、

シンプルにすると、このような実装です。

fail.go
func main() {
    var out []*int
    for i := 0; i < 3; i++ {
        out = append(out, &i)
    }
    fmt.Println("Values:", *out[0], *out[1], *out[2])
    fmt.Println("Addresses:", out[0], out[1], out[2])
}

ValuesもAddressesも[0]~[2]で同じ値が表示されます。
ループカウンタを値渡しではなく、
参照渡しをして保管してしまったことが要因です。

同じような実装ミスをC++で書くとこんな感じです。

fail.cpp
#include <iostream>
#include <vector>

int main(){

    std::vector<int*> out;

    for(int i = 0; i < 3; i++){
        out.push_back(&i);
    }

    std::cout << out[0] << std::endl;
    std::cout << out[1] << std::endl;
    std::cout << out[2] << std::endl;

    std::cout << *out[0] << std::endl;
    std::cout << *out[1] << std::endl;
    std::cout << *out[2] << std::endl;

    return 0;
}

これも同じような結果になります。

Rustで書いてみると

good.rust
fn main() {

    let mut out:Vec<&i32> = vec![];

    for i in 0..3{
        out.push(&i);
    }

    println!("{:?}", out);
}

コンパイル時に、このようなエラーが出ます。

6 |         out.push(&i);
  |         ---      ^^ borrowed value does not live long enough
  |         |
  |         borrow later used here

Rustは生存期間を厳密に検証してくれるので、とても安全です!

実際のLet's encryptの実装ミスは、ループの中で関数呼び出しを挟んでいるので
気づくのが難しいとも感じました。

こんなケースではRustは本当に頼もしいです。

Rustはいいぞ

コンパイラにめっちゃ怒られるぞ。
コンパイラに怒られるのに快感を感じるようになったら立派なRust使いです。

162
46
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
162
46