Skip to content
REFERENCE / ZLIB × LEAN

inflate.c.sync2.lean

Source snapshot · 106dc8358dba6435 · Source at the matching commit ↗

Lean source with line numbers. Follow a line number to locate a statement, or an import to read its dependency.

1import ZlibF.Proof.«inflate.c.sync»
2import ZlibF.Proof.«inflate.c.reset»
3import ZlibF.Proof.«inflate.c.misc»
4
5/-!
6# inflate.c: `inflateSync`
7
8Infrastructure: the local array `unsigned char buf[4]` is a block taken at the start of the call (`syncAlloc`) and
9freed before every return (`freeWin ... buf`); the block number is never reused.
10-/
11
12namespace Zlib.Inflate.Spec
13open C
14
15/-- The initial (arbitrary) content of `buf[4]`. -/
16def syncJunk (h : Heap) : Array UInt8 := Array.ofFn (n := 4) fun i => Junk.of (h.garbage h.nalloc i.val)
17
18/-- The heap after the local array `buf[4]` is made: block `h.nextBlk`, writable. -/
19def syncAlloc (h : Heap) : Heap :=
20  { h with bytes := upd h.bytes h.nextBlk (some (syncJunk h)), ro := upd h.ro h.nextBlk false, nextBlk := h.nextBlk + 1 }
21
22/-- The pointer to the local array. -/
23def syncBuf (h : Heap) : BPtr := .ref (.blk h.nextBlk) 0
24
25/-- The heap after a call that did nothing but make and free the local array. -/
26def tmpFreed (h : Heap) : Heap := freeWin (syncAlloc h) (syncBuf h)
27
28end Zlib.Inflate.Spec
29
30namespace Zlib.Inflate.Proofs
31open C Zlib.Inflate Zlib.Inflate.Spec
32
33theorem allocLocalB_run (h : Heap) (hF : Fresh h) : allocLocalB 4 h = .ok (syncBuf h, syncAlloc h) := by
34  have hs := hF.slotUsed_next
35  simp [allocLocalB, allocBytes, hs, syncBuf, syncAlloc, syncJunk]
36
37@[simp] theorem syncAlloc_streams (h : Heap) : (syncAlloc h).streams = h.streams := rfl
38@[simp] theorem syncAlloc_gzstates (h : Heap) : (syncAlloc h).gzstates = h.gzstates := rfl
39@[simp] theorem syncAlloc_istates (h : Heap) : (syncAlloc h).istates = h.istates := rfl
40@[simp] theorem syncAlloc_words (h : Heap) : (syncAlloc h).words = h.words := rfl
41@[simp] theorem syncAlloc_gzheaders (h : Heap) : (syncAlloc h).gzheaders = h.gzheaders := rfl
42@[simp] theorem syncAlloc_dstates (h : Heap) : (syncAlloc h).dstates = h.dstates := rfl
43@[simp] theorem syncAlloc_nextBlk (h : Heap) : (syncAlloc h).nextBlk = h.nextBlk + 1 := rfl
44@[simp] theorem syncAlloc_nalloc (h : Heap) : (syncAlloc h).nalloc = h.nalloc := rfl
45@[simp] theorem syncAlloc_allocOk (h : Heap) : (syncAlloc h).allocOk = h.allocOk := rfl
46@[simp] theorem syncAlloc_garbage (h : Heap) : (syncAlloc h).garbage = h.garbage := rfl
47@[simp] theorem syncAlloc_static (h : Heap) : (syncAlloc h).static = h.static := rfl
48
49@[simp] theorem ZStreamRef.get_syncAlloc (h : Heap) (r : ZStreamRef) : r.get (syncAlloc h) = r.get h := by
50  cases r <;> rfl
51
52theorem syncAlloc_bytes_buf (h : Heap) : (syncAlloc h).bytes h.nextBlk = some (syncJunk h) := by
53  simp [syncAlloc]
54theorem syncAlloc_ro_buf (h : Heap) : (syncAlloc h).ro h.nextBlk = false := by
55  simp [syncAlloc]
56theorem syncAlloc_bytes_ne (h : Heap) {b : Nat} (hb : b ≠ h.nextBlk) : (syncAlloc h).bytes b = h.bytes b := by
57  simp [syncAlloc, upd_ne _ _ _ _ hb]
58
59theorem fresh_dead {h : Heap} (hF : Fresh h) {b : Nat} (hb : h.nextBlk ≤ b) :
60    h.bytes b = none ∧ h.words b = none ∧ h.streams b = none ∧ h.gzheaders b = none ∧ h.dstates b = none ∧
61    h.istates b = none ∧ h.gzstates b = none :=
62  Heap.not_live.mp (hF b hb)
63
64theorem uniq_syncAlloc {h : Heap} (hU : Uniq h) (hF : Fresh h) : Uniq (syncAlloc h) := by
65  intro b
66  by_cases hb : b = h.nextBlk
67  · subst hb
68    obtain ⟨e0, e1, e2, e3, e4, e5, e6⟩ := fresh_dead hF (Nat.le_refl _)
69    simp [syncAlloc, e1, e2, e3, e4, e5, e6, cnt]
70  · have := hU b
71    simpa [syncAlloc, upd_ne _ _ _ _ hb] using this
72
73theorem fresh_syncAlloc {h : Heap} (hF : Fresh h) : Fresh (syncAlloc h) := by
74  intro b hb hl
75  simp only [syncAlloc_nextBlk] at hb
76  apply hF b (by omega)
77  have hne : b ≠ h.nextBlk := by omega
78  simpa [Heap.live, syncAlloc, upd_ne _ _ _ _ hne] using hl
79
80theorem live_syncAlloc {h : Heap} (b : Nat) : (syncAlloc h).live b ↔ h.live b ∨ b = h.nextBlk := by
81  by_cases hb : b = h.nextBlk
82  · subst hb; simp [Heap.live, syncAlloc]
83  · simp [Heap.live, syncAlloc, upd_ne _ _ _ _ hb, hb]
84
85theorem winInv_syncAlloc {h : Heap} (hF : Fresh h) {st : InflateState} (hW : WinInv h st) : WinInv (syncAlloc h) st := by
86  refine ⟨hW.wbits, ?_, hW.nullws, hW.ws, hW.hv, hW.wn, hW.eq⟩
87  rcases hW.block with hn | ⟨w, a, hw, ha, hro, hsz⟩
88  · exact Or.inl hn
89  · have hwn : w ≠ h.nextBlk := by
90      intro e; subst e
91      obtain ⟨e0, -⟩ := fresh_dead hF (Nat.le_refl _)
92      rw [ha] at e0; cases e0
93    exact Or.inr ⟨w, a, hw, by rw [syncAlloc_bytes_ne h hwn]; exact ha, by simp [syncAlloc, upd_ne _ _ _ _ hwn, hro], hsz⟩
94
95theorem good_syncAlloc {h : Heap} {r : ZStreamRef} {zs : Nat} {z : ZStream} {st : InflateState}
96    (hG : Good h r zs z st) : Good (syncAlloc h) r zs z st := by
97  obtain ⟨⟨hz, hs, zst, back, hm, za, zf⟩, ⟨wf, win, rq, bits, ptr⟩, hU, hF⟩ := hG
98  exact ⟨⟨by simpa using hz, by simpa using hs, zst, back, hm, za, zf⟩,
99    ⟨wf, winInv_syncAlloc hF win, rq, bits, ptr⟩, uniq_syncAlloc hU hF, fresh_syncAlloc hF⟩
100
101theorem live_tmpFreed {h : Heap} (b : Nat) : (tmpFreed h).live b → (syncAlloc h).live b :=
102  live_freeWin _ b
103
104theorem freeBuf_run {H : Heap} {nb : Nat} {a : Array UInt8} (hb : H.bytes nb = some a) (hro : H.ro nb = false) :
105    freeB (.ref (.blk nb) 0) H = .ok ((), freeWin H (.ref (.blk nb) 0)) := by
106  rw [freeB_ok hb hro]; rfl
107
108/-! ### The early returns -/
109
110/-- **inflateSync, refusal.** If the state check fails (`StreamDom`: `NULL`, or a live record whose state is not a usable
111inflate state) the call returns `Z_STREAM_ERROR`; nothing changes except that the local array `buf` was made and freed
112(the block number is used up). -/
113theorem inflateSync_check {h : Heap} (hF : Fresh h) {strm : ZStreamPtr} (hD : StreamDom h strm)
114    (hN : ¬ Initialised h strm) :
115    C.run (inflateSync strm) h = .ok (Z_STREAM_ERROR, tmpFreed h) := by
116  have hD' : StreamDom (syncAlloc h) strm := by
117    rcases hD with h0 | ⟨r, z, h0, hr, hc⟩
118    · exact Or.inl h0
119    · exact Or.inr ⟨r, z, h0, by simpa using hr, by simpa using hc⟩
120  have hN' : ¬ Initialised (syncAlloc h) strm := by
121    rintro ⟨r, zs, z, st, h0, hL⟩
122    exact hN ⟨r, zs, z, st, h0, ⟨by simpa using hL.hz, by simpa using hL.hs, hL.zst, hL.back, hL.mode, hL.zalloc, hL.zfree⟩⟩
123  show inflateSync strm h = _
124  unfold inflateSync
125  have hb : (syncAlloc h).bytes h.nextBlk = some (syncJunk h) := syncAlloc_bytes_buf h
126  simp [bind_app, pure_app, allocLocalB_run h hF, notInit_check hD' hN', freeBuf_run hb (syncAlloc_ro_buf h), tmpFreed,
127    syncBuf]
128
129/-- **inflateSync, no input.** On an initialised stream with `avail_in = 0` and fewer than 8 bits in the bit buffer the
130call returns `Z_BUF_ERROR`; nothing changes except that the local array `buf` was made and freed. -/
131theorem inflateSync_buf_error {h : Heap} {r : ZStreamRef} {zs : Nat} {z : ZStream} {st : InflateState}
132    (hG : Good h r zs z st) (hav : z.avail_in = 0) (hb : st.bits < 8) :
133    C.run (inflateSync (some r)) h = .ok (Z_BUF_ERROR, tmpFreed h) := by
134  have hG' := good_syncAlloc hG
135  have hL := hG'.live
136  show inflateSync (some r) h = _
137  unfold inflateSync
138  have hbb : (syncAlloc h).bytes h.nextBlk = some (syncJunk h) := syncAlloc_bytes_buf h
139  isimp [allocLocalB_run h hG.fresh, stateCheck_live hL, hL.zst, hG.live.hz, hG.live.hs, hav, hb,
140    freeBuf_run hbb (syncAlloc_ro_buf h), tmpFreed, syncBuf]
141
142/-- the part of `inflateSync` from the bit-buffer restore on, as a function of the state pointer -/
143def syncFirst (st : InflateStatePtr) (buf : BPtr) (s : InflateState) : M Unit := do
144  let h ← shr64 s.hold (s.bits &&& 7)
145  wrS st fun s => { s with mode := SYNC, hold := h, bits := s.bits - (s.bits &&& 7) }
146  let len ← cwhile (σ := UInt32)
147    (fun len => do return ((← rdS st (·.bits)) >= 8, len))
148    (fun len => do
149      let s ← ldInflateState st
150      store8 (← buf.add (len.toNat : Int)) s.hold.toUInt8
151      wrS st fun s => { s with hold := s.hold >>> 8, bits := s.bits - 8 }
152      pure (len + 1))
153    0
154  wrS st fun s => { s with «have» := 0 }
155  let (_, hv) ← syncsearch 0 buf len
156  wrS st fun s => { s with «have» := hv }
157
158def syncDone (strm : ZStreamPtr) (st : InflateStatePtr) : M Int32 := do
159    let flags ← rdS st (·.flags)
160    let z ← ldZStream strm
161    let in_ := z.total_in
162    let out_ := z.total_out
163    let _ ← inflateReset strm
164    wrZ strm fun z => { z with total_in := in_, total_out := out_ }
165    wrS st fun s => { s with flags := flags }
166    if flags == -1 then wrS st fun s => { s with wrap := 0 }
167    else wrS st fun s => { s with wrap := s.wrap &&& ~~~4 }
168    let s ← ldInflateState st
169    if s.wbits == 0 then
170      if s.window != .null then
171        ZFREEB strm s.window
172        wrS st fun s => { s with window := .null }
173      wrS st fun s => { s with wbits := 15 }
174    setMode st TYPE
175    return Z_OK
176
177def syncTail (strm : ZStreamPtr) (st : InflateStatePtr) : M Int32 := do
178    let z ← ldZStream strm
179    let (len, hv) ← syncsearch (← rdS st (·.«have»)) z.next_in z.avail_in
180    wrS st fun s => { s with «have» := hv }
181    let ni ← z.next_in.add (len.toNat : Int)
182    wrZ strm fun z => { z with avail_in := z.avail_in - len, next_in := ni, total_in := z.total_in + len.toUInt64 }
183    if (← rdS st (·.«have»)) != 4 then return Z_DATA_ERROR
184    syncDone strm st
185
186theorem bind_ite_unit {α : Type} (c : Prop) [Decidable c] (A : M Unit) (jp : Unit → M α) :
187    (ite c A (pure ()) >>= jp) = ite c (A >>= jp) (jp ()) := by
188  by_cases hc : c <;> simp [hc] <;> rfl
189
190theorem bind_assoc_M {α β γ : Type} (m : M α) (f : α → M β) (g : β → M γ) :
191    ((m >>= f) >>= g) = (m >>= fun x => f x >>= g) := by
192  funext h
193  simp only [bind_app]
194  cases m h with
195  | error e => rfl
196  | ok p => rfl
197
198theorem inflateSync_split (strm : ZStreamPtr) : inflateSync strm = (do
199  let buf ← allocLocalB 4
200  let r ← (do
201    if (← inflateStateCheck strm) != 0 then return Z_STREAM_ERROR
202    let z ← ldZStream strm
203    let st ← castInflateState z.state
204    let s ← ldInflateState st
205    if z.avail_in == 0 && s.bits < 8 then return Z_BUF_ERROR
206    if s.mode != SYNC then syncFirst st buf s
207    syncTail strm st)
208  freeB buf
209  return r) := by
210  unfold inflateSync syncFirst syncTail syncDone
211  simp only [bind_assoc_M]
212
213end Zlib.Inflate.Proofs
214
215namespace Zlib.Inflate.Spec
216open C
217
218/-- The state record after `inflateReset`, the restored flags and the wrapper change of `inflateSync`, before the window
219bits are looked at: the request is raw if no header was read (`flags = -1`), else the check bit is cleared. -/
220def syncC (zs : Nat) (s : InflateState) : InflateState :=
221  let sB := { resetKeepState zs (resetPre s) with flags := s.flags }
222  if s.flags == -1 then { sB with wrap := 0 } else { sB with wrap := sB.wrap &&& ~~~4 }
223
224/-- The state record after a successful `inflateSync` search: reset to wait for a block type (`TYPE`), the header flags
225kept, a window size that no header ever gave set to 15 (the window is dropped then). -/
226def syncOkState (zs : Nat) (s : InflateState) : InflateState :=
227  let sC := syncC zs s
228  { (if sC.wbits == 0 then { sC with window := .null, wbits := 15 } else sC) with mode := TYPE }
229
230/-- The stream record after a successful `inflateSync` search: reset (`inflateReset`) but `total_in` and `total_out`
231keep their values. `z` is the record after the search consumed its bytes. -/
232def syncOkStream (z : ZStream) (s : InflateState) : ZStream :=
233  { resetKeepStream z (resetPre s) with total_in := z.total_in, total_out := z.total_out }
234
235/-- The heap after a successful `inflateSync` search, from the heap `H` (the stream record `z` after the search, the state
236record `s`): the reset frees the window if its size is not the requested one; a window size of 0 frees the window. -/
237def syncOkHeap (H : Heap) (r : ZStreamRef) (zs : Nat) (z : ZStream) (s : InflateState) : Heap :=
238  let X := setI (r.put (resetHeap H s) (syncOkStream z s)) zs (syncOkState zs s)
239  if (syncC zs s).wbits == 0 then freeWin X (syncC zs s).window else X
240
241end Zlib.Inflate.Spec
242
243namespace Zlib.Inflate.Proofs
244open C Zlib.Inflate Zlib.Inflate.Spec
245
246/-- **inflateSync, found.** From a good stream (`zfree` the default) the part of `inflateSync` after the pattern is found
247returns `Z_OK` with the heap `syncOkHeap`: reset, `total_in`/`total_out` kept, mode `TYPE`. -/
248theorem syncDone_run {H : Heap} {r : ZStreamRef} {zs : Nat} {z : ZStream} {s : InflateState}
249    (hG : Good H r zs z s) (hf : z.zfree = .fn "zcfree") :
250    syncDone (some r) (some (.tab zs)) H = .ok (Z_OK, syncOkHeap H r zs z s) := by
251  have hL := hG.live
252  have hwo : s.wbits = s.reqbits ∨ WindowOk H s.window := Or.inr (windowBlock hG.inv.win)
253  have hz0 : r.get (resetHeap H s) = some z := by unfold resetHeap; split <;> simp [hL.hz]
254  have hs0 : (resetHeap H s).istates zs = some s := by unfold resetHeap; split <;> simp [hL.hs]
255  unfold syncDone
256  isimp [stateCheck_live hL, hL.zst, hL.hz, hL.hs]
257  rw [inflateReset_run hL hf hwo]
258  have hrb : (resetPre s).wbits = s.reqbits := by unfold resetPre; split <;> simp_all
259  have hwb := windowBlock (winInv_reset hG.inv.win hG.inv.reqbits)
260  unfold syncOkHeap syncOkState syncOkStream syncC
261  generalize resetPre s = sR at hrb hwb ⊢
262  have hzN : r.get (setI (r.put (resetHeap H s) { resetKeepStream z sR with total_in := z.total_in, total_out := z.total_out }) zs
263      (resetKeepState zs sR)) = some { resetKeepStream z sR with total_in := z.total_in, total_out := z.total_out } := by
264    simp [hz0]
265  by_cases hfl : s.flags = -1
266  · by_cases h0 : sR.wbits = 0
267    · rcases hwb with hn | ⟨b, a, hb, hba, hro⟩
268      · isimp [hz0, hs0, resetKeepState, hfl, h0, hn, freeWin_null, setMode]
269      · isimp [hz0, hs0, resetKeepState, hfl, h0, hb, setMode]
270        rw [zfreeB_run (r := r) (z := { resetKeepStream z sR with total_in := z.total_in, total_out := z.total_out })
271          (p := .ref (.blk b) 0) (by simp [hz0]) (by simpa [resetKeepStream] using hf) (Or.inr ⟨b, a, rfl, by simpa using hba, by simpa using hro⟩)]
272        isimp [setMode, freeWin_istates]
273    · isimp [hz0, hs0, resetKeepState, hfl, h0, setMode]
274  · by_cases h0 : sR.wbits = 0
275    · rcases hwb with hn | ⟨b, a, hb, hba, hro⟩
276      · isimp [hz0, hs0, resetKeepState, hfl, h0, hn, freeWin_null, setMode]
277      · isimp [hz0, hs0, resetKeepState, hfl, h0, hb, setMode]
278        rw [zfreeB_run (r := r) (z := { resetKeepStream z sR with total_in := z.total_in, total_out := z.total_out })
279          (p := .ref (.blk b) 0) (by simp [hz0]) (by simpa [resetKeepStream] using hf) (Or.inr ⟨b, a, rfl, by simpa using hba, by simpa using hro⟩)]
280        isimp [setMode, freeWin_istates]
281    · isimp [hz0, hs0, resetKeepState, hfl, h0, setMode]
282
283/-! ### The invariants after a found pattern -/
284
285theorem resetPre_win (st : InflateState) : (resetPre st).wsize = 0 ∧ (resetPre st).whave = 0 ∧ (resetPre st).wnext = 0 := by
286  unfold resetPre; split <;> simp
287
288theorem resetPre_wbits (st : InflateState) : (resetPre st).wbits = st.reqbits := by
289  unfold resetPre; split <;> simp_all
290
291theorem resetPre_strm (st : InflateState) : (resetPre st).strm = st.strm := by
292  unfold resetPre; split <;> simp
293
294theorem syncC_field (zs : Nat) (s : InflateState) :
295    (syncC zs s).wbits = s.reqbits ∧ (syncC zs s).window = (resetPre s).window ∧ (syncC zs s).wsize = 0 ∧
296    (syncC zs s).whave = 0 ∧ (syncC zs s).wnext = 0 ∧ (syncC zs s).reqbits = s.reqbits ∧ (syncC zs s).strm = s.strm ∧
297    (syncC zs s).bits = 0 ∧ (syncC zs s).lens = s.lens ∧ (syncC zs s).work = s.work ∧ (syncC zs s).codes = s.codes := by
298  obtain ⟨a1, a2, a3⟩ := resetPre_win s
299  have a4 := resetPre_wbits s
300  have a5 := resetPre_strm s
301  have a6 : (resetPre s).reqbits = s.reqbits := reqbits_resetPre s
302  have a7 : (resetPre s).lens = s.lens := by unfold resetPre; split <;> simp
303  have a8 : (resetPre s).work = s.work := by unfold resetPre; split <;> simp
304  have a9 : (resetPre s).codes = s.codes := by unfold resetPre; split <;> simp
305  unfold syncC
306  split <;> simp [resetKeepState, a1, a2, a3, a4, a5, a6, a7, a8, a9]
307
308theorem syncC_ptr (zs : Nat) (s : InflateState) :
309    (syncC zs s).next = .ref (.istate_codes zs) 0 ∧ (syncC zs s).lencode = .ref (.istate_codes zs) 0 ∧
310    (syncC zs s).distcode = .ref (.istate_codes zs) 0 := by
311  unfold syncC; split <;> simp [resetKeepState]
312
313theorem syncOkState_eq0 {zs : Nat} {s : InflateState} (h0 : s.reqbits = 0) :
314    syncOkState zs s = { syncC zs s with window := .null, wbits := 15, mode := TYPE } := by
315  unfold syncOkState
316  simp [(syncC_field zs s).1, h0]
317
318theorem syncOkState_ne0 {zs : Nat} {s : InflateState} (h0 : s.reqbits ≠ 0) :
319    syncOkState zs s = { syncC zs s with mode := TYPE } := by
320  unfold syncOkState
321  simp [(syncC_field zs s).1, h0]
322
323/-- The state record after a found pattern satisfies the representation invariant on the heap after the reset. -/
324theorem syncOk_inv {H : Heap} {r : ZStreamRef} {zs : Nat} {z : ZStream} {s : InflateState} (hG : Good H r zs z s) :
325    StInv (resetHeap H s) zs (syncOkState zs s) := by
326  have hwf := wf_resetPre hG.inv.wf
327  have hwr := winInv_reset hG.inv.win hG.inv.reqbits
328  obtain ⟨f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11⟩ := syncC_field zs s
329  obtain ⟨p1, p2, p3⟩ := syncC_ptr zs s
330  have hwf' : s.WellFormed := hG.inv.wf
331  have hrq := hG.inv.reqbits
332  by_cases h0 : s.reqbits = 0
333  · rw [syncOkState_eq0 h0]
334    refine ⟨?_, ?_, ?_, ?_, ?_⟩
335    · unfold InflateState.WellFormed at hwf' ⊢
336      simp only [f9, f10, f11]; exact hwf'
337    · refine ⟨by simp, Or.inl rfl, fun _ => by simpa using f3, Or.inl (by simp [f3]), by simp [f3, f4], Or.inr ⟨by simp [f3], by simp [f5]⟩, fun hh => by simp [f3, f4] at hh⟩
338    · simpa [f6] using hrq
339    · simp [syncC, resetKeepState]; split <;> simp
340    · exact ⟨⟨0, by simp [p1], by omega⟩, Or.inl ⟨0, 0, by simp [p2], by simp [p3], by omega, by omega⟩⟩
341  · rw [syncOkState_ne0 h0]
342    refine ⟨?_, ?_, ?_, ?_, ?_⟩
343    · unfold InflateState.WellFormed at hwf' ⊢
344      simp only [f9, f10, f11]; exact hwf'
345    · have hb : (resetPre s).wbits.toNat ≤ 15 := hwr.wbits
346      refine ⟨by simpa [f1, resetPre_wbits] using hrq, ?_, fun hn => ?_, Or.inl (by simp [f3]), by simp [f3, f4], Or.inr ⟨by simp [f3], by simp [f5]⟩, fun hh => by simp [f3, f4] at hh⟩
347      · have := hwr.block
348        simpa [f2, f1, resetPre_wbits] using this
349      · simp [f3]
350    · simpa [f6] using hrq
351    · simp [syncC, resetKeepState]; split <;> simp
352    · exact ⟨⟨0, by simp [p1], by omega⟩, Or.inl ⟨0, 0, by simp [p2], by simp [p3], by omega, by omega⟩⟩
353
354theorem winInv_of_null {H H' : Heap} {st : InflateState} (hW : WinInv H' st) (hn : st.window = .null) : WinInv H st :=
355  ⟨hW.wbits, Or.inl hn, hW.nullws, hW.ws, hW.hv, hW.wn, hW.eq⟩
356
357theorem stInv_of_null {H H' : Heap} {zs : Nat} {st : InflateState} (hI : StInv H' zs st) (hn : st.window = .null) :
358    StInv H zs st :=
359  ⟨hI.wf, winInv_of_null hI.win hn, hI.reqbits, hI.bits, hI.ptr⟩
360
361theorem syncOk_window_null {zs : Nat} {s : InflateState} (h0 : s.reqbits = 0) : (syncOkState zs s).window = .null := by
362  rw [syncOkState_eq0 h0]
363
364/-- The window of the state is kept by a found pattern: it has the requested size, and the size is not 0. -/
365def SyncKeeps (s : InflateState) : Prop := s.wbits = s.reqbits ∧ s.reqbits ≠ 0
366
367theorem resetPre_window (st : InflateState) :
368    (resetPre st).window = if st.wbits = st.reqbits then st.window else .null := by
369  unfold resetPre; split <;> simp_all
370
371/-- After a found pattern the stream is good again and the live blocks only shrink. -/
372theorem syncDone_good {H : Heap} {r : ZStreamRef} {zs : Nat} {z : ZStream} {s : InflateState}
373    (hG : Good H r zs z s) :
374    Good (syncOkHeap H r zs z s) r zs (syncOkStream z s) (syncOkState zs s) ∧
375    (∀ b, (syncOkHeap H r zs z s).live b → H.live b) := by
376  have hL := hG.live
377  have hU : Uniq (resetHeap H s) := by
378    unfold resetHeap; split
379    · exact uniq_freeWin hG.uniq _
380    · exact hG.uniq
381  have hF : Fresh (resetHeap H s) := by
382    unfold resetHeap; split
383    · exact fresh_freeWin hG.fresh _
384    · exact hG.fresh
385  have hz0 : r.get (resetHeap H s) = some z := by unfold resetHeap; split <;> simp [hL.hz]
386  have hs0 : (resetHeap H s).istates zs = some s := by unfold resetHeap; split <;> simp [hL.hs]
387  obtain ⟨f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11⟩ := syncC_field zs s
388  have hmode : HEAD ≤ (syncOkState zs s).mode ∧ (syncOkState zs s).mode ≤ SYNC := by
389    have : (syncOkState zs s).mode = TYPE := by unfold syncOkState; simp
390    rw [this]; decide
391  have hback : (syncOkState zs s).strm = some r := by
392    have : (syncOkState zs s).strm = s.strm := by
393      unfold syncOkState; simp [f7]
394      split <;> simp [f7]
395    rw [this]; exact hL.back
396  have hX : Good (setI (r.put (resetHeap H s) (syncOkStream z s)) zs (syncOkState zs s)) r zs (syncOkStream z s)
397      (syncOkState zs s) :=
398    good_set hz0 hs0 hU hF (by simp [syncOkStream, resetKeepStream, hL.zst]) (by simpa [syncOkStream, resetKeepStream] using hL.zalloc)
399      (by simpa [syncOkStream, resetKeepStream] using hL.zfree) hback hmode (syncOk_inv hG)
400  have hShape : Shape (resetHeap H s) (setI (r.put (resetHeap H s) (syncOkStream z s)) zs (syncOkState zs s)) :=
401    (shape_put hz0 _).trans (shape_setI (by simpa using hs0) _)
402  have hlive0 : ∀ b, (resetHeap H s).live b → H.live b := by
403    intro b hb
404    unfold resetHeap at hb; split at hb
405    · exact live_freeWin _ b hb
406    · exact hb
407  by_cases h0 : s.reqbits = 0
408  · have hc : ((syncC zs s).wbits == 0) = true := by simp [f1, h0]
409    have hHeap : syncOkHeap H r zs z s = freeWin (setI (r.put (resetHeap H s) (syncOkStream z s)) zs (syncOkState zs s)) (resetPre s).window := by
410      unfold syncOkHeap; simp [hc, f2]
411    rw [hHeap]
412    have hwn : (syncOkState zs s).window = .null := syncOk_window_null h0
413    exact ⟨⟨⟨by simpa using hX.live.hz, by simpa using hX.live.hs, hX.live.zst, hX.live.back, hX.live.mode, hX.live.zalloc, hX.live.zfree⟩,
414      stInv_of_null hX.inv hwn, uniq_freeWin hX.uniq _, fresh_freeWin hX.fresh _⟩,
415      fun b hb => hlive0 b ((hShape.live b).1 (live_freeWin _ b hb))⟩
416  · have hc : ¬ ((syncC zs s).wbits == 0) = true := by simp [f1, h0]
417    have hHeap : syncOkHeap H r zs z s = setI (r.put (resetHeap H s) (syncOkStream z s)) zs (syncOkState zs s) := by
418      unfold syncOkHeap; simp [hc]
419    rw [hHeap]
420    exact ⟨hX, fun b hb => hlive0 b ((hShape.live b).1 hb)⟩
421
422/-- Ownership after a found pattern: only the window block can be freed (`¬ SyncKeeps`); nothing is allocated. -/
423theorem syncDone_owns {H : Heap} {r : ZStreamRef} {zs : Nat} {z : ZStream} {s : InflateState}
424    (hG : Good H r zs z s) {S : Nat → Prop} (hO : H.Owns S) :
425    (syncOkHeap H r zs z s).Owns (fun b => S b ∧ ¬ (¬ SyncKeeps s ∧ WinBlk s b)) := by
426  have hL := hG.live
427  have hz0 : r.get (resetHeap H s) = some z := by unfold resetHeap; split <;> simp [hL.hz]
428  have hs0 : (resetHeap H s).istates zs = some s := by unfold resetHeap; split <;> simp [hL.hs]
429  obtain ⟨f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11⟩ := syncC_field zs s
430  have hShape : Shape (resetHeap H s) (setI (r.put (resetHeap H s) (syncOkStream z s)) zs (syncOkState zs s)) :=
431    (shape_put hz0 _).trans (shape_setI (by simpa using hs0) _)
432  have hO2 := hShape.owns (resetHeap_owns hG.uniq hG.inv.win hO)
433  have hwb := windowBlock (winInv_reset hG.inv.win hG.inv.reqbits)
434  have hrw := resetPre_window s
435  by_cases h0 : s.reqbits = 0
436  · have hc : ((syncC zs s).wbits == 0) = true := by simp [f1, h0]
437    have hHeap : syncOkHeap H r zs z s = freeWin (setI (r.put (resetHeap H s) (syncOkStream z s)) zs (syncOkState zs s)) (resetPre s).window := by
438      unfold syncOkHeap; simp [hc, f2]
439    rw [hHeap]
440    rcases hwb with hn | ⟨w, a, hw, hba, hro⟩
441    · rw [hn, freeWin_null]
442      intro b; rw [hO2 b]
443      by_cases hwr : s.wbits = s.reqbits
444      · rw [hwr] at hrw
445        simp only [ite_true] at hrw
446        have : ¬ WinBlk s b := by
447          intro hb; unfold WinBlk at hb; rw [hrw] at hn; simp [hb] at hn
448        simp [SyncKeeps, this, hwr]
449      · simp [SyncKeeps, hwr]
450    · have hwr : s.wbits = s.reqbits := by
451        by_cases hh : s.wbits = s.reqbits
452        · exact hh
453        · rw [ite_eq_right hh] at hrw; rw [hrw] at hw; cases hw
454      rw [ite_eq_left hwr] at hrw
455      have hUX : Uniq (setI (r.put (resetHeap H s) (syncOkStream z s)) zs (syncOkState zs s)) :=
456        hShape.uniq (by
457          unfold resetHeap; split
458          · exact uniq_freeWin hG.uniq _
459          · exact hG.uniq)
460      have hbX : (setI (r.put (resetHeap H s) (syncOkStream z s)) zs (syncOkState zs s)).bytes w = some a := by simpa using hba
461      have := owns_freeWin hUX hbX hO2
462      rw [hw]
463      intro b
464      rw [this b]
465      have hws : s.window = .ref (.blk w) 0 := by rw [← hrw]; exact hw
466      have hWB : WinBlk s b ↔ b = w := by
467        unfold WinBlk; rw [hws]
468        constructor
469        · intro hh; exact (BRef.blk.inj (Ptr.ref.inj hh).1).symm
470        · intro hh; rw [hh]
471      simp [SyncKeeps, hwr, h0, hWB]
472  · have hc : ¬ ((syncC zs s).wbits == 0) = true := by simp [f1, h0]
473    have hHeap : syncOkHeap H r zs z s = setI (r.put (resetHeap H s) (syncOkStream z s)) zs (syncOkState zs s) := by
474      unfold syncOkHeap; simp [hc]
475    rw [hHeap]
476    intro b; rw [hO2 b]
477    simp [SyncKeeps, h0]
478
479end Zlib.Inflate.Proofs
480
481namespace Zlib.Inflate.Spec
482open C
483
484/-- The search state `g` is consistent with the bytes `w` seen so far: either the pattern has not occurred and `g` is the
485longest proper prefix of it that ends `w` (`SyncSt`), or the pattern has occurred in `w` and `g = 4`. -/
486def SyncAt (g : UInt32) (w : List UInt8) : Prop := SyncSt g w ∨ (g = 4 ∧ syncPat <:+: w)
487
488/-- `p + n` for a pointer into a block (`NULL` stays `NULL`: only `n = 0` occurs there). -/
489def syncAdv (p : BPtr) (n : Nat) : BPtr := match p with | .null => .null | .ref r o => .ref r (o + n)
490
491/-- The stream record after the search consumed `N` bytes of input: `avail_in` down, `next_in` and `total_in` up. -/
492def syncAdvance (z : ZStream) (N : UInt32) : ZStream :=
493  { z with avail_in := z.avail_in - N, next_in := syncAdv z.next_in N.toNat, total_in := z.total_in + N.toUInt64 }
494
495end Zlib.Inflate.Spec
496
497namespace Zlib.Inflate.Proofs
498open C Zlib.Inflate Zlib.Inflate.Spec
499
500theorem syncsearch_at {h : Heap} {p : BPtr} {len : UInt32} {bs : List UInt8} (I : SyncIn h p len bs)
501    {g : UInt32} {w : List UInt8} (hA : SyncAt g w) :
502    ∃ N G, syncsearch g p len h = .ok ((N, G), h) ∧ N.toNat ≤ len.toNat ∧
503      (G = 4 → syncPat <:+: w ++ bs.take N.toNat ∧ ∀ L', L' < N.toNat → ¬ syncPat <:+: w ++ bs.take L') ∧
504      (G ≠ 4 → N = len ∧ SyncSt G (w ++ bs)) := by
505  rcases hA with hs | ⟨rfl, hw⟩
506  · obtain ⟨N, G, hr, h1, h2, h3⟩ := syncsearch_spec I hs
507    refine ⟨N, G, hr, h1, ?_, h3⟩
508    intro h4
509    obtain ⟨-, a, b⟩ := h2 h4
510    exact ⟨List.IsSuffix.isInfix a, b⟩
511  · have hlen := syncIn_length I
512    rcases I with ⟨b, a, o, rfl, hg, hl, rfl⟩ | ⟨rfl, rfl, rfl⟩
513    · have := syncsearch_run (r := .blk b) (h := h) (a := a) (o := o) (len := len) 4 hg hl
514      rw [syncScan_ge (by decide)] at this
515      refine ⟨0, 4, by simpa using this, by simp, fun _ => ⟨by simpa using hw, fun L' hL' => by simp at hL'⟩, fun h4 => absurd rfl h4⟩
516    · refine ⟨0, 4, syncsearch_null 4 h, by simp, fun _ => ⟨by simpa using hw, fun L' hL' => by simp at hL'⟩, fun h4 => absurd rfl h4⟩
517
518/-- Reading the search result into the stream: advancing the input pointer by `N ≤ len` bytes. -/
519theorem syncAdd_run {H : Heap} {p : BPtr} {len : UInt32} {bs : List UInt8} (I : SyncIn H p len bs) {N : UInt32}
520    (hN : N.toNat ≤ len.toNat) {H' : Heap} (hb : H'.bytes = H.bytes) :
521    Ptr.add p (N.toNat : Int) H' = .ok (syncAdv p N.toNat, H') := by
522  rcases I with ⟨b, a, o, rfl, hg, hl, rfl⟩ | ⟨rfl, rfl, rfl⟩
523  · have hg' : Space.get H' (BRef.blk b) = some a := by simpa [Space.get, hb] using hg
524    exact Ptr.add_nat_ok (r := BRef.blk b) hg' (by omega)
525  · have : N.toNat = 0 := by simpa using hN
526    rw [this]; rfl
527
528/-- The state record after the search: only `have` changes. -/
529def syncHave (s : InflateState) (G : UInt32) : InflateState := { s with «have» := G }
530
531theorem good_syncSearch {H : Heap} {r : ZStreamRef} {zs : Nat} {z : ZStream} {s : InflateState}
532    (hG : Good H r zs z s) (N : UInt32) (G : UInt32) :
533    Good (setI (r.put H (syncAdvance z N)) zs (syncHave s G)) r zs (syncAdvance z N) (syncHave s G) :=
534  hG.setZI (by simp [syncAdvance]) (by simpa [syncAdvance] using hG.live.zalloc)
535    (by simpa [syncAdvance] using hG.live.zfree) (by simp [syncHave]) (by simpa [syncHave] using hG.live.mode)
536    (hG.inv.of_fields rfl rfl rfl rfl rfl rfl rfl rfl rfl hG.inv.bits rfl rfl rfl)
537
538/-- **The search step of `inflateSync`.** On a stream in the search (`Good`, with the state's `have` consistent with the
539bytes `w` seen so far, `SyncAt`) and an input `next_in[0 .. avail_in)` (`SyncIn`), the part of `inflateSync` from the call
540of `syncsearch` on runs without a fault. It stores the search result in `have`, consumes `N` bytes (`syncAdvance`) and
541returns `Z_DATA_ERROR` if the pattern is not complete (`G ≠ 4`, and then all the input was consumed), else `Z_OK` after the
542reset of the stream (`syncOkHeap`). -/
543theorem syncTail_run {H : Heap} {r : ZStreamRef} {zs : Nat} {z : ZStream} {s : InflateState} {bs w : List UInt8}
544    (hG : Good H r zs z s) (hf : z.zfree = .fn "zcfree") (hI : SyncIn H z.next_in z.avail_in bs)
545    (hA : SyncAt s.«have» w) :
546    ∃ N G, N.toNat ≤ z.avail_in.toNat ∧
547      (G = 4 → syncPat <:+: w ++ bs.take N.toNat ∧ ∀ L', L' < N.toNat → ¬ syncPat <:+: w ++ bs.take L') ∧
548      (G ≠ 4 → N = z.avail_in ∧ SyncSt G (w ++ bs)) ∧
549      Good (setI (r.put H (syncAdvance z N)) zs (syncHave s G)) r zs (syncAdvance z N) (syncHave s G) ∧
550      (G ≠ 4 → syncTail (some r) (some (.tab zs)) H =
551        .ok (Z_DATA_ERROR, setI (r.put H (syncAdvance z N)) zs (syncHave s G))) ∧
552      (G = 4 → syncTail (some r) (some (.tab zs)) H =
553        .ok (Z_OK, syncOkHeap (setI (r.put H (syncAdvance z N)) zs (syncHave s G)) r zs (syncAdvance z N) (syncHave s G))) := by
554  have hL := hG.live
555  obtain ⟨N, G, hse, hN, h4, h3⟩ := syncsearch_at hI hA
556  have hG1 := good_syncSearch hG N G
557  refine ⟨N, G, hN, h4, h3, hG1, fun hne => ?_, fun he => ?_⟩
558  · unfold syncTail
559    isimp [hL.hz, hL.hs, hse, syncAdd_run hI hN (H' := setI H zs { s with «have» := G }) rfl, syncAdvance, syncHave, hne]
560  · subst he
561    unfold syncTail
562    have hdone := syncDone_run (hG1) (by simpa [syncAdvance] using hf)
563    isimp [hL.hz, hL.hs, hse, syncAdd_run hI hN (H' := setI H zs { s with «have» := 4 }) rfl]
564    simpa [syncAdvance, syncHave] using hdone
565
566end Zlib.Inflate.Proofs
ZLIB × LEAN

Global contents

READING NOWinflate.c.sync2.lean