参考文档 / ZLIB × LEAN
gzlib.c.error.lean
此页源文件快照 ·
9cf97640b4bd2d97 · 对应提交的原文 ↗本页保留 Lean 源码及行号。点击行号可定位语句,点击 import 中的模块名可查看依赖。
1import ZlibF.Proof.«gzlib.c.base»
2
3/-!
4# gzlib.c: `gz_error` without a message, `gz_reset`, `gzclearerr`
5
6`gz_error(state, err, NULL)` frees the old message, records `err` and clears the message. `gz_reset` is made of plain
7field writes and one such call. Both keep `GzGood` (the message block is the only block that goes away) and give the
8ownership statement: the live blocks afterwards are those before, without the old message block.
9-/
10
11namespace Zlib.Gzlib.Spec
12open C Zlib.GzFs Zlib.Gzguts
13
14/-- The record `gz_error(state, err, NULL)` leaves: no message, the new error code. -/
15def errNull (s : GzState) (e : Int32) : GzState := { s with msg := .null, err := e }
16
17/-- The record `gz_reset` leaves (`gz_reset(state)` after `gz_open` and in `gzrewind`): the buffered bytes and the
18position are cleared, the reader goes back to `LOOK`, the writer clears `reset`, the error is `Z_OK` without a message,
19and the embedded stream has no input. -/
20def resetRec (s : GzState) : GzState :=
21 { (if s.mode == GZ_READ then { s with eof := 0, how := LOOK, junk := -1 } else { s with reset := 0 }) with
22 x := { s.x with «have» := 0, pos := 0 }, past := 0, again := 0, skip := 0, msg := .null, err := Z_OK,
23 strm := { s.strm with avail_in := 0 } }
24
25end Zlib.Gzlib.Spec
26
27namespace Zlib.Gzlib.Proofs
28open C Zlib.GzFs Zlib.Gzguts Zlib.Gzlib Zlib.Gzlib.Spec
29
30theorem blk_ne_msg {h : Heap} {gs : Nat} {s : GzState} (hG : GzGood h gs s) {mb : Nat} (hm : s.msg = .ref (.blk mb) 0) :
31 (∀ b, s.path = .ref (.blk b) 0 → b ≠ mb) ∧ (∀ b, s.in = .ref (.blk b) 0 → b ≠ mb) ∧
32 (∀ b, s.out = .ref (.blk b) 0 → b ≠ mb) := by
33 have hn := hG.nodup
34 rcases hG.path with ⟨pb, hp, -⟩
35 rcases hG.inb with hi | ⟨ib, ia, hi, -⟩ <;> rcases hG.outb with ho | ⟨ob, oa, ho, -⟩ <;>
36 simp [hp, hm, hi, ho, ptrBlk, List.nodup_cons] at hn ⊢ <;> omega
37
38theorem Uniq.freeBytes {h : Heap} (hU : Uniq h) (mb : Nat) : Uniq { h with bytes := upd h.bytes mb none } := by
39 intro b
40 by_cases hb : b = mb
41 · subst hb
42 have := hU b
43 simp only [upd_same, cnt_none]
44 omega
45 · have := hU b
46 simpa only [upd_ne _ _ _ _ hb] using this
47
48theorem live_freeBytes {h : Heap} (hU : Uniq h) {mb : Nat} {a : Array UInt8} (ha : h.bytes mb = some a) (b : Nat) :
49 ({ h with bytes := upd h.bytes mb none } : Heap).live b ↔ h.live b ∧ b ≠ mb := by
50 by_cases hb : b = mb
51 · subst hb
52 have := hU b
53 simp only [Heap.live, ha, cnt_some] at this ⊢
54 simp only [upd_same]
55 have h1 : h.words b = none := by
56 cases hh : h.words b <;> simp [hh] at this ⊢ <;> omega
57 have h2 : h.streams b = none := by
58 cases hh : h.streams b <;> simp [hh] at this ⊢ <;> omega
59 have h3 : h.gzheaders b = none := by
60 cases hh : h.gzheaders b <;> simp [hh] at this ⊢ <;> omega
61 have h4 : h.dstates b = none := by
62 cases hh : h.dstates b <;> simp [hh] at this ⊢ <;> omega
63 have h5 : h.istates b = none := by
64 cases hh : h.istates b <;> simp [hh] at this ⊢ <;> omega
65 have h6 : h.gzstates b = none := by
66 cases hh : h.gzstates b <;> simp [hh] at this ⊢ <;> omega
67 simp [h1, h2, h3, h4, h5, h6]
68 · simp [Heap.live, upd_ne _ _ _ _ hb, hb]
69
70theorem Fresh.freeBytes {h : Heap} (hF : Fresh h) (mb : Nat) : Fresh { h with bytes := upd h.bytes mb none } := by
71 intro b hb hl
72 apply hF b hb
73 by_cases hbm : b = mb
74 · subst hbm
75 simp only [Heap.live, upd_same] at hl ⊢
76 rcases hl with hl | hl
77 · exact absurd rfl hl
78 · exact Or.inr hl
79 · simpa [Heap.live, upd_ne _ _ _ _ hbm] using hl
80
81theorem nodup_drop_msg {a c d : BPtr} (b : BPtr) (hn : ([a, b, c, d].filterMap ptrBlk).Nodup) :
82 ([a, (.null : BPtr), c, d].filterMap ptrBlk).Nodup := by
83 have e : ([a, (.null : BPtr), c, d].filterMap ptrBlk) = ([a, c, d].filterMap ptrBlk) := by
84 simp [List.filterMap_cons, ptrBlk]
85 rw [e]
86 exact List.Nodup.sublist (List.Sublist.filterMap ptrBlk (by simp)) hn
87
88/-- `gz_error(state, e, NULL)` keeps the invariant (the old message block is freed). -/
89theorem GzGood.afterErr {h : Heap} {gs : Nat} {s : GzState} (hG : GzGood h gs s) (e : Int32) :
90 GzGood (setS (freeStr h s.msg) gs (errNull s e)) gs (errNull s e) := by
91 rcases hG.msg with hn | ⟨mb, hm, a, ha, hro, k, hz⟩
92 · rw [hn]; simp only [freeStr_null]
93 exact GzGood.withRec hG (Or.inl rfl) rfl (by simp [errNull, hn]) rfl rfl (by simp [errNull])
94 · obtain ⟨hpn, hin, hon⟩ := blk_ne_msg hG hm
95 rw [hm]; simp only [freeStr_blk]
96 have hU := Uniq.freeBytes hG.uniq mb
97 have hF := Fresh.freeBytes hG.fresh mb
98 have hS := shape_setS (h := ({ h with bytes := upd h.bytes mb none } : Heap)) (gs := gs) (s0 := s) hG.hs (errNull s e)
99 refine ⟨by simp, hG.mode, ?_, Or.inl rfl, ?_, ?_, nodup_drop_msg s.msg hG.nodup, fun _ => rfl,
100 Shape.uniq hS hU, Shape.fresh hS rfl hF⟩
101 · obtain ⟨pb, hp, a', ha', hro', k', hz'⟩ := hG.path
102 have hne := hpn pb hp
103 exact ⟨pb, hp, a', by simp [setS, upd_ne _ _ _ _ hne, ha'], by simpa using hro', k', hz'⟩
104 · rcases hG.inb with hi | ⟨ib, ia, hi, hia, hiro⟩
105 · exact Or.inl hi
106 · have hne := hin ib hi
107 exact Or.inr ⟨ib, ia, hi, by simp [setS, upd_ne _ _ _ _ hne, hia], by simpa using hiro⟩
108 · rcases hG.outb with hi | ⟨ib, ia, hi, hia, hiro⟩
109 · exact Or.inl hi
110 · have hne := hon ib hi
111 exact Or.inr ⟨ib, ia, hi, by simp [setS, upd_ne _ _ _ _ hne, hia], by simpa using hiro⟩
112
113
114@[simp] theorem freeStr_setS (h : Heap) (gs : Nat) (s : GzState) (p : BPtr) :
115 freeStr (setS h gs s) p = setS (freeStr h p) gs s := by
116 cases p with
117 | null => rfl
118 | ref r o => cases r <;> rfl
119
120theorem freeB_blk_run {h : Heap} {mb : Nat} {a : Array UInt8} (ha : h.bytes mb = some a) (hro : h.ro mb = false) :
121 freeB (.ref (.blk mb) 0) h = .ok ((), { h with bytes := upd h.bytes mb none }) := by
122 simp [freeB, ha, hro]
123
124theorem freeB_blk_setS {h : Heap} {mb : Nat} {a : Array UInt8} (ha : h.bytes mb = some a) (hro : h.ro mb = false)
125 (gs : Nat) (s' : GzState) :
126 freeB (.ref (.blk mb) 0) (setS h gs s') = .ok ((), setS { h with bytes := upd h.bytes mb none } gs s') := by
127 simp [freeB, setS, ha, hro]
128
129theorem record_msg_null {s : GzState} (hn : s.msg = .null) : { s with msg := .null } = s := by
130 cases s; simp_all
131
132/-- `gz_error(state, err, NULL)`: the old message is freed (the only change of the heap besides the record), the error
133code is `err` and there is no message. -/
134theorem gz_error_null_run {h : Heap} {gs : Nat} {s : GzState} (hG : GzGood h gs s) (e : Int32) :
135 gz_error (some (.tab gs)) e .null h = .ok ((), setS (freeStr h s.msg) gs (errNull s e)) := by
136 have hs := hG.hs
137 unfold gz_error
138 rcases hG.msg with hn | ⟨mb, hm, a, ha, hro, k, hz⟩
139 · gsimp [hs, hn, errNull]
140 · have hne : s.err ≠ Z_MEM_ERROR := fun h' => by have := hG.memerr h'; rw [hm] at this; cases this
141 gsimp [hs, hm, hne, freeB_blk_run ha hro, freeB_blk_setS ha hro, errNull]
142
143
144/-- `gz_reset(state)`. -/
145theorem gz_reset_run {h : Heap} {gs : Nat} {s : GzState} (hG : GzGood h gs s) :
146 gz_reset (some (.tab gs)) h = .ok ((), setS (freeStr h s.msg) gs (resetRec s)) := by
147 have hs := hG.hs
148 unfold gz_reset
149 rcases hG.msg with hn | ⟨mb, hm, a, ha, hro, k, hz⟩
150 · by_cases hmo : s.mode = GZ_READ
151 · gsimp [hs, hn, hmo, gz_error, resetRec]
152 · gsimp [hs, hn, hmo, gz_error, resetRec]
153 · have hne : s.err ≠ Z_MEM_ERROR := fun h' => by have := hG.memerr h'; rw [hm] at this; cases this
154 by_cases hmo : s.mode = GZ_READ
155 · gsimp [hs, hm, hne, hmo, freeB_blk_setS ha hro, gz_error, resetRec]
156 · gsimp [hs, hm, hne, hmo, freeB_blk_setS ha hro, gz_error, resetRec]
157
158theorem GzGood.afterReset {h : Heap} {gs : Nat} {s : GzState} (hG : GzGood h gs s) :
159 GzGood (setS (freeStr h s.msg) gs (resetRec s)) gs (resetRec s) := by
160 have h1 := GzGood.withRec (GzGood.afterErr hG Z_OK) (s' := resetRec s) (Or.inl (by unfold resetRec errNull; split <;> rfl))
161 (by unfold resetRec errNull; split <;> rfl) (by unfold resetRec errNull; split <;> rfl)
162 (by unfold resetRec errNull; split <;> rfl) (by unfold resetRec errNull; split <;> rfl)
163 (by intro _; unfold resetRec; split <;> rfl)
164 simpa using h1
165
166/-- **gz_reset, safety and effect.** On a handle that satisfies the invariant the call does not fault; the old message
167block is the only block freed; the record is `resetRec s`. -/
168theorem gz_reset_safe {h : Heap} {gs : Nat} {s : GzState} (hG : GzGood h gs s) :
169 ∃ h', C.run (gz_reset (some (.tab gs))) h = .ok ((), h') ∧ h' = setS (freeStr h s.msg) gs (resetRec s) ∧
170 GzGood h' gs (resetRec s) ∧
171 (∀ S, h.Owns S → h'.Owns (fun b => S b ∧ s.msg ≠ .ref (.blk b) 0)) := by
172 refine ⟨_, gz_reset_run hG, rfl, GzGood.afterReset hG, ?_⟩
173 intro S hO
174 rcases hG.msg with hn | ⟨mb, hm, a, ha, hro, k, hz⟩
175 · simp only [hn, freeStr_null]
176 have := Shape.owns (shape_setS hG.hs (resetRec s)) hO
177 simpa [hn] using this
178 · rw [hm]; simp only [freeStr_blk]
179 have hO1 : ({ h with bytes := upd h.bytes mb none } : Heap).Owns (fun b => S b ∧ b ≠ mb) := by
180 intro b; rw [live_freeBytes hG.uniq ha b, hO b]
181 have := Shape.owns (shape_setS (h := ({ h with bytes := upd h.bytes mb none } : Heap)) (gs := gs) (s0 := s) hG.hs (resetRec s)) hO1
182 intro b
183 rw [this b]
184 simp [hm, eq_comm]
185
186end Zlib.Gzlib.Proofs