Slide 1

Slide 1 text

1 Gobra で見る形式検証 mercari.go #26 2024/6/18 @kobaryo

Slide 2

Slide 2 text

2 
 Merpay Partner Platform 
 バックエンドエンジニア 
 
 2024年4月新卒入社 
 kobaryo 
 artoy
 @artoy5884

Slide 3

Slide 3 text

3 ● Goal ○ Gobra で何ができるかざっくりと把握する ○ 形式検証を使うべきタイミングが分かる ● Non-Goal ○ Gobra で Go プログラムを検証する具体的なアノテーションの書き方を身に付ける 今回のGoal

Slide 4

Slide 4 text

4 目次 1 形式検証のメリット 2 Gobra 3 形式検証のデメリット

Slide 5

Slide 5 text

5 目次 1 形式検証のメリット 2 Gobra 3 形式検証のデメリット

Slide 6

Slide 6 text

6 ● プログラムが仕様を満たしていることを数学的手法を用いて証明すること ○ 実際にプログラムを動かすことなく証明ができる ● 実は我々は型という軽量な形式検証を利用している 形式検証とは?

Slide 7

Slide 7 text

7 ● テストの問題点を解決できる ○ 有限通りしかチェックできない ○ 実際にシステムを動かすのが大変な場合がある ■ ロケット・列車・原子炉など 形式検証のメリット

Slide 8

Slide 8 text

8 目次 1 形式検証のメリット 2 Gobra a. Gobra とは b. インターフェースを含むプログラムの検証 c. Goroutine を含むプログラムの検証 3 形式検証のデメリット

Slide 9

Slide 9 text

9 ● Go プログラムの検証器 ○ アノテーション付きの Go プログラムを 入力すれば検証結果を出力してくれる ● 主に関数の仕様について検証可能 ● Go の主要な機能に対応している ○ 組み込みのデータ型 ○ インターフェース ○ Goroutine ● CAV 2021 で発表 ● 実装は Scala ● VSCodeの拡張機能も提供されている Gobra https://github.com/viperproject/gobra

Slide 10

Slide 10 text

10 関数の仕様の検証 関数の実行前に 成り立っている 事前条件 関数の実行後に 成り立っている 事後条件 仕 様

Slide 11

Slide 11 text

11 ● Gobra はインターフェースについてモジュラーに検証可能 ○ インターフェースの実装を後から増やしても、インターフェースを再検証する 必要がない インターフェースを含むプログラムの検証

Slide 12

Slide 12 text

12 type SomeInterface interface { require A ensure B func f {...} } 実装を増やして仕様が変わってしまう例 require C ensure D func (s SomeStruct) f {...} SomeStruct の f は、SomeInterface の f の仕様を満たしているとは限らない → インターフェースの仕様を 再証明する必 要性 追加 証明済み

Slide 13

Slide 13 text

13 type SomeInterface interface { require A ensure B func f {...} } Gobra におけるモジュラーな検証 require C ensure D func (s SomeStruct) f {...} 追加 証明済み (SomeStruct) implements SomeInterface { (s SomeStruct) f { // A ⟹ C と D ⟹ B の証明 } } SomeStruct の f が、SomeInterface の f の仕様を満たしていること の証明をプ ログラマが書けば再証明しなくて OK Behavioral Subtyping

Slide 14

Slide 14 text

14 ensure *x == old(*x) + 1 func inc(x *int) { *x = *x + 1 } ensure x == 3 func concurrentInc() { x := 1 go inc(&x) go inc(&x) } Goroutine を含むプログラムの検証例 Goroutine 1 Goroutine 2 Read / Write Read / Write

Slide 15

Slide 15 text

15 ensure *x == old(*x) + 1 func inc(x *int) { *x = *x + 1 } ensure x == 3 func concurrentInc() { x := 1 go inc(&x) go inc(&x) } Goroutine を含むプログラムの検証例 1 Goroutine 1 Goroutine 2 Read / Write Read / Write

Slide 16

Slide 16 text

16 ensure *x == old(*x) + 1 func inc(x *int) { *x = *x + 1 } ensure x == 3 func concurrentInc() { x := 1 go inc(&x) go inc(&x) } Goroutine を含むプログラムの検証例 1 1 Goroutine 1 Goroutine 2 Read / Write Read / Write

Slide 17

Slide 17 text

17 ensure *x == old(*x) + 1 func inc(x *int) { *x = *x + 1 } ensure x == 3 func concurrentInc() { x := 1 go inc(&x) go inc(&x) } Goroutine を含むプログラムの検証例 1 2 Goroutine 1 1 Goroutine 2 Read / Write Read / Write ポインタの指す 先が更新される 前に読み込み

Slide 18

Slide 18 text

18 ensure *x == old(*x) + 1 func inc(x *int) { *x = *x + 1 } ensure x == 3 func concurrentInc() { x := 1 go inc(&x) go inc(&x) } Goroutine を含むプログラムの検証例 2 2 Goroutine 1 2 Goroutine 2 Read / Write Read / Write 3にならない可能性がある → Failにしなければならない

Slide 19

Slide 19 text

19 ● Fractional permission を使って、レースコンディションを防ぐ ○ 並行プログラミングだけでなく、エイリアシングによる検証の問題も解決 Gobra による Goroutine を含むプログラムの検証

Slide 20

Slide 20 text

20 Fractional Permission v Pointer 1 Pointer 2 v Pointer 1 Pointer 2 v Pointer 1 Pointer 2 🙆 󰢃 Read / Write Read Read Read Read / Write Rust の所有権・借 用と大体同じ ここの行き来は人間が 書く必要がある

Slide 21

Slide 21 text

21 Gobra によるレースコンディションの防止例 x の Read / Write 権限を持っている 1行上の inc(&x) の &x が Write 権限を 持っているので、この inc は requiresで ある acc を達成できない → Fail

Slide 22

Slide 22 text

22 Gobra による Mutex を使った検証例 Lock の Permission LockしてUnlockすると Lock の Permission と x の Write 権限が返ってくる

Slide 23

Slide 23 text

23 目次 1 形式検証のメリット 2 Gobra 3 形式検証のデメリット

Slide 24

Slide 24 text

24 🤯 アノテーションが多い! Gobra のアノテーション付きコード例 ・ ・ ・

Slide 25

Slide 25 text

25 Gobra におけるアノテーションの量 LOC が元の Go プログラムの行数、Spec がアノテーションの行数 最大でプログラム の3倍!

Slide 26

Slide 26 text

26 ● Gobra に限らず、一般に形式検証には大きなデメリットがある ○ アノテーションを書くのが大変 ○ 計算量が大きい(手法によっては停止するとも限らない) ○ 仕様を正しく定めるのが難しい ■ 林晋「あるソフトウェア工学者の失敗」 形式検証のデメリット

Slide 27

Slide 27 text

27 ● Gobra は Go の多くの機能をサポートするプログラム検証器 ○ インターフェース ○ Goroutine ● 形式検証はテストの問題点を解決するが、まだ大きな欠点が残っている ○ それでもやはり形式検証はパワフルな技法なので、デメリットを受け入れた上で使う タイミングを見極めたい まとめ

Slide 28

Slide 28 text

28 ● Felix A. Wolf, Linard Arquint, Martin Clochard, Wytse Oortwijn, João C. Pereira, & Peter Müller. (2021). Gobra: Modular Specification and Verification of Go Programs (extended version). ● A Tutorial on Gobra https://github.com/viperproject/gobra/blob/master/docs/tutorial. md 参考文献