Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Verified Software Toolchain C ~Coqを用いたCプログラムの検証~

unisuke
December 11, 2021

Verified Software Toolchain C ~Coqを用いたCプログラムの検証~

unisuke

December 11, 2021
Tweet

More Decks by unisuke

Other Decks in Technology

Transcript

  1. Verified Software Toolchain C Cプログラムの関数的な正しさを証明するためのツールセットのこと • 分離論理に基づいたVerifiable Cと呼ばれるプログラム論理 • VST-Floydと呼ばれる証明⾃動化システム

    • Coqによる健全性証明、プログラムについて証明したいかなる性質も、Cソース⾔語の操作セマンティクスのい かなる実⾏においても実際に成⽴することを保証します。この証明は、CompCertで検証された最適化Cコンパ イラの正しさの証明と組み合わされているので、アセンブリ⾔語プログラムの動作についても保証されます。
  2. 検証するCプログラム #include <stddef.h> unsigned sumarray(unsigned a[], int n) { int

    i; unsigned s; i=0; s=0; while (i<n) { s+=a[i]; i++; } return s; } unsigned four[4] = {1,2,3,4}; int main(void) { unsigned int s; s = sumarray(four,4); return (int)s; } sumarray.v
  3. sumarrayの関数仕様 Definition sumarray_spec : ident × funspec := DECLARE _sumarray

    WITH a: val, sh : share, contents : list Z, size: Z PRE [ tptr tuint, tint ] PROP (readable_share sh; 0 ≤ size ≤ Int.max_signed; Forall (fun x ⇒ 0 ≤ x ≤ Int.max_unsigned) contents) PARAMS (a; Vint (Int.repr size)) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a) POST [ tuint ] PROP () RETURN (Vint (Int.repr (sum_Z contents))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a).
  4. sumarrayの関数仕様 • DECLAREステートメントはident × funspec型 → 関数名と関数仕様を関連づけている Definition sumarray_spec :

    ident × funspec := DECLARE _sumarray WITH a: val, sh : share, contents : list Z, size: Z PRE [ tptr tuint, tint ] PROP (readable_share sh; 0 ≤ size ≤ Int.max_signed; Forall (fun x ⇒ 0 ≤ x ≤ Int.max_unsigned) contents) PARAMS (a; Vint (Int.repr size)) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a) POST [ tuint ] PROP () RETURN (Vint (Int.repr (sum_Z contents))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a).
  5. sumarrayの関数仕様 • 関数はその前提条件と後条件によって定められる • PRE節 : 前提条件 • POST節 :

    後条件 • WITH節 : 前提条件と後条件の両⽅に出現する可能性のあるCoq値を定量化する Definition sumarray_spec : ident × funspec := DECLARE _sumarray WITH a: val, sh : share, contents : list Z, size: Z PRE [ tptr tuint, tint ] PROP (readable_share sh; 0 ≤ size ≤ Int.max_signed; Forall (fun x ⇒ 0 ≤ x ≤ Int.max_unsigned) contents) PARAMS (a; Vint (Int.repr size)) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a) POST [ tuint ] PROP () RETURN (Vint (Int.repr (sum_Z contents))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a).
  6. sumarrayの関数仕様 • PRE節POST節の中⾝はどちらもPROP(P) LOCAL(Q) SEP(R)の形をとる Definition sumarray_spec : ident ×

    funspec := DECLARE _sumarray WITH a: val, sh : share, contents : list Z, size: Z PRE [ tptr tuint, tint ] PROP (readable_share sh; 0 ≤ size ≤ Int.max_signed; Forall (fun x ⇒ 0 ≤ x ≤ Int.max_unsigned) contents) PARAMS (a; Vint (Int.repr size)) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a) POST [ tuint ] PROP () RETURN (Vint (Int.repr (sum_Z contents))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a).
  7. sumarrayの関数仕様 PROP(P) LOCAL(Q) SEP(R) • PROP(P) • PはCoqのPropでプログラムの状態と関係なく真 • LOCAL(Q)

    • Cプログラムのローカル変数の中⾝を記述するが、⽂脈によって異なる形をとる • 前提条件内ではPARAMS節で関数のパラメータを順に記述する • 後条件内ではRETURN節で関数の返り値を記述する • 関数本体の中ではパラメータを含むローカル変数を記述するためにLOCAL節を⽤いる • SEP(R) • Rは分離論理の空間アサーション • 後条件のSEP節では前提条件のSEP節で記述されている空間資源から解放されたものを除いてmalloc割り当 てされたものを加える
  8. sumarrayの関数仕様 • [ tuint ]unsigned int型を返すことを⽰す • PROPが空なので関数⼊⼒時に真だった事実が保持されていないとわかる • Return節からcontentsの各要素の合計を返り値とすることがわかる

    • SEPではメモリアドレスaにarray[size] of unsigned int 型のデータ構造が存在することをアクセス許可を⽰す shと共に記述している Definition sumarray_spec : ident × funspec := DECLARE _sumarray WITH a: val, sh : share, contents : list Z, size: Z PRE [ tptr tuint, tint ] PROP (readable_share sh; 0 ≤ size ≤ Int.max_signed; Forall (fun x ⇒ 0 ≤ x ≤ Int.max_unsigned) contents) PARAMS (a; Vint (Int.repr size)) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a) POST [ tuint ] PROP () RETURN (Vint (Int.repr (sum_Z contents))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a).
  9. mainの関数仕様 Definition main_spec := DECLARE _main WITH gv : globals

    PRE [] main_pre prog tt gv POST [ tint ] PROP() RETURN (Vint (Int.repr (1+2+3+4))) SEP(TT).
  10. 関数仕様をまとめる • Definition Gprog := [sumarray_spec; main_spec]. • GprogにはDECLAREで構築したfunspecが⼊っている •

    Vprogはグローバル変数の型指定のリストが⼊っていて、これは⾃動で計算される Print Vprog. (* = (_four, tarray tuint 4) : varspecs *) Print varspecs. (* = list (ident * type) *) script
  11. f_sumarrayがsumarray_specを満たすことの証明 • グローバvルコンテキスト(Vprog,Gprog)において、sumarray()関数の本体であるf_sumarrayがsumarray_spec を満たすことを証明する Lemma body_sumarray: semax_body Vprog Gprog f_sumarray

    sumarray_spec. Proof. 1 goal (ID 72) ============================ semax_body Vprog Gprog f_sumarray sumarray_spec script goal • 述語semax_bodyは関数本体のホーアトリプルDelta ⊢ {Pre} c {Post}を述べている。 • Pre, Post : funspecから取られる • c : 関数本体 • Delta : 型コンテキスト,関数のパラメータの型とローカル変数の型を重ねたグローバル型コンテクストか ら計算される
  12. • start_functionタクティクで証明されるべき ホーアトリプルを表現する … start_function. 1 goal (ID 72) ============================

    semax_body Vprog Gprog f_sumarray sumarray_spec script goal 1 goal (ID 469) Espec : OracleKind a : val sh : share contents : list Z size : Z Delta_specs : Maps.PTree.t funspec Delta := abbreviate : tycontext SH : readable_share sh H : 0 <= size <= Int.max_signed H0 : Forall (fun x : Z => 0 <= x <= Int.max_unsigned) contents POSTCONDITION := abbreviate : ret_assert MORE_COMMANDS := abbreviate : statement ============================ semax Delta (PROP ( ) LOCAL (temp _a a; temp _n (Vint (Int.repr size))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a)) (_i = (0); MORE_COMMANDS) POSTCONDITION goal
  13. • forwardタクティクでホーアトリプルの証明規則を 適⽤する … forward. . . . ============================ semax

    Delta (PROP ( ) LOCAL (temp _a a; temp _n (Vint (Int.repr size))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a)) (_i = (0); MORE_COMMANDS) POSTCONDITION script goal . . . ============================ semax Delta (PROP ( ) LOCAL (temp _i (Vint (Int.repr 0)); temp _a a; temp _n (Vint (Int.repr size))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a)) (_s = (0); MORE_COMMANDS) POSTCONDITION goal {P}(i=0;){Q} {Q}(...more...){R} --------------------------------- {P}(i=0;...more...){R} • 推論規則の適⽤によって証明すべきホーアトリプルが上段2つに変化。右の証明に当たって前提条件がPからQ に変化 • temp _i (Vint (Int.repr 0))はローカル変数の定義を⽰す
  14. • forwardタクティクでホーアトリプルの証明規則を 適⽤する … forward. . . . LOOP_BODY :=

    abbreviate : statement ============================ semax Delta (PROP ( ) LOCAL (temp _s (Vint (Int.repr 0)); temp _i (Vint (Int.repr 0)); temp _a a; temp _n (Vint (Int.repr size))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a)) (while (_i < _n) { LOOP_BODY } MORE_COMMANDS) POSTCONDITION script goal . . . ============================ semax Delta (PROP ( ) LOCAL (temp _i (Vint (Int.repr 0)); temp _a a; temp _n (Vint (Int.repr size))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a)) (_s = (0); MORE_COMMANDS) POSTCONDITION goal {P}(s=0;){Q} {Q}(...more...){R} --------------------------------- {P}(s=0;...more...){R}
  15. • ループの評価にはforward_whileタクティクを⽤いる • forward_whileタクティクにはループ不変条件を与える • forward_whileタクティク実⾏後のゴールは以下 1. ループ全体の前提条件がループ不変条件であること 2. ループ条件式の型チェック

    3. ループの中⾝の後条件がループ不変条件であること 4. ループ不変条件がループ後のMORE_COMMANDSを証明するの に⼗分に強⼒な前提条件であること loop test loop body true false 不変条件 … forward_while (EX i: Z, PROP (0 <= i <= size) LOCAL (temp _a a; temp _i (Vint (Int.repr i)); temp _n (Vint (Int.repr size)); temp _s (Vint (Int.repr (sum_Z (sublist 0 i contents))))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a)). script
  16. 1. ループ全体の前提条件がループ不変条件であることの証明 goal . . . ============================ ENTAIL Delta, PROP

    ( ) LOCAL (temp _s (Vint (Int.repr 0)); temp _i (Vint (Int.repr 0)); temp _a a; temp _n (Vint (Int.repr size))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a) |-- EX i : Z, PROP (0 <= i <= size) LOCAL (temp _a a; temp _i (Vint (Int.repr i)); temp _n (Vint (Int.repr size)); temp _s (Vint (Int.repr (sum_Z (sublist 0 i contents))))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a) • 証明のゴールはENTAIL Delta, P |-- Q,の形をした分離論理の論理的帰結 • ENTAIL Delta, P |-- Qは「コンテキストDeltaの元でPを満たす任意の状態がQを満たす」の意
  17. • Existsタクティクを使って量化変数の値を⽰す … Exists 0. . . . ============================ ENTAIL

    Delta, PROP ( ) LOCAL (temp _s (Vint (Int.repr 0)); temp _i (Vint (Int.repr 0)); temp _a a; temp _n (Vint (Int.repr size))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a) |-- PROP (0 <= 0 <= size) LOCAL (temp _a a; temp _i (Vint (Int.repr 0)); temp _n (Vint (Int.repr size)); temp _s (Vint (Int.repr (sum_Z (sublist 0 0 contents))))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a) script goal . . . ============================ ENTAIL Delta, PROP ( ) LOCAL (temp _s (Vint (Int.repr 0)); temp _i (Vint (Int.repr 0)); temp _a a; temp _n (Vint (Int.repr size))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a) |-- EX i : Z, PROP (0 <= i <= size) LOCAL (temp _a a; temp _i (Vint (Int.repr i)); temp _n (Vint (Int.repr size)); temp _s (Vint (Int.repr (sum_Z (sublist 0 i contents))))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a) goal
  18. 2. ループ条件式の型チェック goal . . . i : Z ============================

    ENTAIL Delta, PROP (0 <= i <= size) LOCAL (temp _a a; temp _i (Vint (Int.repr i)); temp _n (Vint (Int.repr size)); temp _s (Vint (Int.repr (sum_Z (sublist 0 i contents))))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a) |-- tc_expr Delta (!(_i < _n))%expr • ループテスト式がクラッシュせずに評価できること、つまり参照する全ての変数が存在、初期化されているこ と、0で割り切れないことを証明する。これを型チェック条件とよび、述語をtc_expr としている。 • この場合ではループのi<nを証明する必要があるので右辺はtc_expr Delta (!(_i < _n))になっている
  19. 3.ループの中⾝の後条件がループ不変条件であること goal . . . i : Z HRE :

    i < size H1 : 0 <= i <= size POSTCONDITION := abbreviate : ret_assert MORE_COMMANDS := abbreviate : statement ============================ semax Delta (PROP ( ) LOCAL (temp _a a; temp _i (Vint (Int.repr i)); temp _n (Vint (Int.repr size)); temp _s (Vint (Int.repr (sum_Z (sublist 0 i contents))))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a)) ((_t'1 = _a[_i]; _s = (_s + _t'1);) MORE_COMMANDS) POSTCONDITIONx • ループ不変条件が成⽴している上で、ループの中⾝を実⾏した時に後条件がループ不変条件と⼀致しているこ とを証明する • POSTCONDITIONがループ不変条件、cはループの中⾝
  20. • _t‘1 = _a[_i]の評価を進めるためにforwardタクティクがを実⾏したいが、失敗する • iが配列aの境界内にあることを先に証明する必要がある • HRE : i

    < size, H1 : 0 <= i <= size が仮定に存在しているのでZlength contents = sizeが 証明できれば⼗分。 • この証明に必要な情報はsemax goalの仮定条件内のdata_at sh (tarray tuint size) (map Vint (map Int.repr contents)) aから得られる。data_at述語は、配列の “contents ”リストが配列のサイズ と全く同じ⻑さであることを常に強制する。アサーションで前提条件の事実を⽤いるにはassert_PROPを⽤い る。
  21. • Zlength contents = sizeを⽰す … assert_PROP (Zlength contents =

    size). script goal . . . ============================ ENTAIL Delta, PROP ( ) LOCAL (temp _a a; temp _i (Vint (Int.repr i)); temp _n (Vint (Int.repr size)); temp _s (Vint (Int.repr (sum_Z (sublist 0 i contents))))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a) |-- !! (Zlength contents = size)
  22. • 証明のゴールが論理的帰結になっているので簡単に するためにentailer!タクティクを実⾏ … entailer!. . . . HRE :

    i < Zlength (map Vint (map Int.repr contents)) PNa : is_pointer_or_null a H2 : field_compatible (Tarray tuint (Zlength (map Vint (map Int.repr contents))) noattr) [] a H3 : Forall (value_fits tuint) (map Vint (map Int.repr contents)) ============================ Zlength contents = Zlength (map Vint (map Int.repr contents)) script goal . . . ============================ ENTAIL Delta, PROP ( ) LOCAL (temp _a a; temp _i (Vint (Int.repr i)); temp _n (Vint (Int.repr size)); temp _s (Vint (Int.repr (sum_Z (sublist 0 i contents))))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a) |-- !! (Zlength contents = size) goal
  23. • Zlength_map = forall (A B : Type) (f :

    A -> B) (l : list A), Zlength (map f l) = Zlength l • Zlength_mapを⽤いて書き換えると両辺が等しい ことが証明できる … rewrite Zlength_map. rewrite Zlength_map. reflexivity. script
  24. • Zlength contents = sizeが証明されたため forwardタクティクが実⾏できるようになる … forward. . .

    . ============================ semax Delta (PROP ( ) LOCAL (temp _t'1 (Vint (Int.repr (Znth i contents))); temp _a a; temp _i (Vint (Int.repr i)); temp _n (Vint (Int.repr size)); temp _s (Vint (Int.repr (sum_Z (sublist 0 i contents))))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a)) (_s = (_s + _t'1); MORE_COMMANDS) POSTCONDITION script goal . . . H2 : Zlength contents = size ============================ semax Delta (PROP ( ) LOCAL (temp _a a; temp _i (Vint (Int.repr i)); temp _n (Vint (Int.repr size)); temp _s (Vint (Int.repr (sum_Z (sublist 0 i contents))))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a)) ((_t'1 = _a[_i]; _s = (_s + _t'1);) MORE_COMMANDS) POSTCONDITION goal
  25. • forwardタクティクでホーアトリプルの証明規則を 適⽤する … forward. . . . ============================ semax

    Delta (PROP ( ) LOCAL (temp _s (Vint(Int.add (Int.repr (sum_Z (sublist 0 i contents))) (Int.repr (Znth i contents)))); temp _t'1 (Vint (Int.repr (Znth i contents))); temp _a a; temp _i (Vint (Int.repr i)); temp _n (Vint (Int.repr size))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a)) (_i = (_i + (1));) POSTCONDITION script goal . . . ============================ semax Delta (PROP ( ) LOCAL (temp _t'1 (Vint (Int.repr (Znth i contents))); temp _a a; temp _i (Vint (Int.repr i)); temp _n (Vint (Int.repr size)); temp _s (Vint (Int.repr (sum_Z (sublist 0 i contents))))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a)) (_s = (_s + _t'1); MORE_COMMANDS) POSTCONDITION goal
  26. • forwardタクティクでホーアトリプルの証明規則を 適⽤する … forward. . . . ============================ ENTAIL

    Delta, PROP ( ) LOCAL (temp _i (Vint (Int.add (Int.repr i) (Int.repr 1))); temp _s (Vint (Int.add (Int.repr (sum_Z (sublist 0 i contents))) (Int.repr (Znth i contents)))); temp _t'1 (Vint (Int.repr (Znth i contents))); temp _a a; temp _n (Vint (Int.repr size))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a) |-- EX a0 : Z, PROP (0 <= a0 <= size) LOCAL (temp _a a; temp _i (Vint (Int.repr a0)); temp _n (Vint (Int.repr size)); temp _s (Vint (Int.repr (sum_Z (sublist 0 a0 contents))))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a) script goal . . . ============================ semax Delta (PROP ( ) LOCAL (temp _s (Vint(Int.add (Int.repr (sum_Z (sublist 0 i contents))) (Int.repr (Znth i contents)))); temp _t'1 (Vint (Int.repr (Znth i contents))); temp _a a; temp _i (Vint (Int.repr i)); temp _n (Vint (Int.repr size))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a)) (_i = (_i + (1));) POSTCONDITION goal
  27. • Existsタクティクを使って量化変数の値を⽰す … Exists (i+1). . . . ============================ ENTAIL

    Delta, PROP ( ) LOCAL (temp _i (Vint (Int.add (Int.repr i) (Int.repr 1))); temp _s (Vint (Int.add (Int.repr (sum_Z (sublist 0 i contents))) (Int.repr (Znth i contents)))); temp _t'1 (Vint (Int.repr (Znth i contents))); temp _a a; temp _n (Vint (Int.repr size))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a) |-- PROP (0 <= i + 1 <= size) LOCAL (temp _a a; temp _i (Vint (Int.repr (i + 1))); temp _n (Vint (Int.repr size)); temp _s (Vint (Int.repr (sum_Z (sublist 0 (i + 1) contents))))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a) script goal . . . ============================ ENTAIL Delta, PROP ( ) LOCAL (temp _i (Vint (Int.add (Int.repr i) (Int.repr 1))); temp _s (Vint (Int.add (Int.repr (sum_Z (sublist 0 i contents))) (Int.repr (Znth i contents)))); temp _t'1 (Vint (Int.repr (Znth i contents))); temp _a a; temp _n (Vint (Int.repr size))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a) |-- EX a0 : Z, PROP (0 <= a0 <= size) LOCAL (temp _a a; temp _i (Vint (Int.repr a0)); temp _n (Vint (Int.repr size)); temp _s (Vint (Int.repr (sum_Z (sublist 0 a0 contents))))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a) goal
  28. • entailer! タクティクで論理的帰結を簡約する … entailer!. script . . . ============================

    Vint (Int.repr (sum_Z (sublist 0 (i + 1) contents))) = Vint (Int.repr (sum_Z (sublist 0 i contents) + Znth i contents)) goal . . . ============================ ENTAIL Delta, PROP ( ) LOCAL (temp _i (Vint (Int.add (Int.repr i) (Int.repr 1))); temp _s (Vint (Int.add (Int.repr (sum_Z (sublist 0 i contents))) (Int.repr (Znth i contents)))); temp _t'1 (Vint (Int.repr (Znth i contents))); temp _a a; temp _n (Vint (Int.repr size))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a) |-- PROP (0 <= i + 1 <= size) LOCAL (temp _a a; temp _i (Vint (Int.repr (i + 1))); temp _n (Vint (Int.repr size)); temp _s (Vint (Int.repr (sum_Z (sublist 0 (i + 1) contents))))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a) goal
  29. • f_equal : forall (A B : Type) (f :

    A - > B) (x y : A), x = y -> f x = f y • f_equalを⽤いて書き換える … f_equal. f_equal. script . . . ============================ sum_Z (sublist 0 (i + 1) contents) = sum_Z (sublist 0 i contents) + Znth i contents goal . . . ============================ Vint (Int.repr (sum_Z (sublist 0 (i + 1) contents))) = Vint (Int.repr (sum_Z (sublist 0 i contents) + Znth i contents)) goal
  30. • 左辺を書き換えて右辺と等しいことを⽰す … rewrite (sublist_split 0 i (i+1) contents) by

    lia. rewrite sum_Z_app. rewrite (sublist_one i (i+1) contents) by lia. simpl. lia. script
  31. 4.ループ不変条件とループテストの否定の組み合わせを前提条件としてその後のMORE_COMMANDSを証明する goal 1 goal (ID 1818) Espec : OracleKind a

    : val sh : share contents : list Z size : Z Delta_specs : Maps.PTree.t funspec Delta := abbreviate : tycontext SH : readable_share sh H : 0 <= size <= Int.max_signed H0 : Forall (fun x : Z => 0 <= x <= Int.max_unsigned) contents POSTCONDITION := abbreviate : ret_assert i : Z HRE : i >= size H1 : 0 <= i <= size ============================ semax Delta (PROP ( ) LOCAL (temp _a a; temp _i (Vint (Int.repr i)); temp _n (Vint (Int.repr size)); temp _s (Vint (Int.repr (sum_Z (sublist 0 i contents))))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a)) (return _s;) POSTCONDITION
  32. • return⽂は常にforwardタクティクで評価を進め られる … forward. PNa : is_pointer_or_null a H2

    : field_compatible (Tarray tuint (Zlength (map Vint (map Int.repr contents))) noattr) [] a H3 : Forall (value_fits tuint) (map Vint (map Int.repr contents)) ============================ data_at sh (tarray tuint (Zlength (map Vint (map Int.repr contents)))) (map Vint (map Int.repr contents)) a |-- !! (Vint (Int.repr (sum_Z (sublist 0 i contents))) = Vint (Int.repr (sum_Z contents))) script goal . . . ============================ semax Delta (PROP ( ) LOCAL (temp _a a; temp _i (Vint (Int.repr i)); temp _n (Vint (Int.repr size)); temp _s (Vint (Int.repr (sum_Z (sublist 0 i contents))))) SEP (data_at sh (tarray tuint size) (map Vint (map Int.repr contents)) a)) (return _s;) POSTCONDITION goal
  33. • entailer! タクティクで論理的帰結を簡約する … entailer!. script . . . ============================

    Vint (Int.repr (sum_Z (sublist 0 i contents))) = Vint (Int.repr (sum_Z contents)) goal . . . PNa : is_pointer_or_null a H2 : field_compatible (Tarray tuint (Zlength (map Vint (map Int.repr contents))) noattr) [] a H3 : Forall (value_fits tuint) (map Vint (map Int.repr contents)) ============================ data_at sh (tarray tuint (Zlength (map Vint (map Int.repr contents)))) (map Vint (map Int.repr contents)) a |-- !! (Vint (Int.repr (sum_Z (sublist 0 i contents))) = Vint (Int.repr (sum_Z contents))) goal
  34. f_mainがmain_specを満たすことの証明 • グローバルコンテキスト(Vprog,Gprog)において、main()関数の本体であるf_mainがmain_specを満たすことを 証明する Definition four_contents := [1; 2; 3;

    4]. Lemma body_main: semax_body Vprog Gprog f_main main_spec. Proof. start_function. forward_call (* s = sumarray(four,4); *) (gv _four, Ews, four_contents, 4). repeat constructor; computable. forward. (* return s; *) Qed. script
  35. 全ての関数を結びつける • Cプログラムは⼊出⼒を⾏い、外界に影響を与えることがある • この状態を記述したのがEspec(外部仕様) • sumarray関数は⼊出⼒を⾏わないために⾃明なEspecを使⽤できる • semax_prog prog

    Vprog Gprogという判定は、“varspecがVprogでfunspecがGprogのプログラムprogでは、 Gprogで⾔及されているすべての関数がその仕様を満たしている。”という意 Lemma prog_correct: semax_prog prog tt Vprog Gprog. Proof. prove_semax_prog. semax_func_cons body_sumarray. semax_func_cons body_main. Qed. script