Skip to content
REFERENCE / ZLIB × LEAN

deflate.c.init.default.lean

Source snapshot · 86c269733e51d7bf · 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.«deflate.c.life.reset»
2import ZlibF.Proof.«deflate.c.life.end»
3import ZlibF.Proof.«deflate.c.init.memory»
4import ZlibF.Proof.«trees.c.monad»
5import ZlibF.Spec.Public.Initialisation
6
7/-! # deflate.c: direct proof of the default initialization entry
8
9The public default entry is proved by expanding its fixed-parameter call.
10No universal deflateInit2_ execution theorem is used or assumed.
11-/
12
13namespace Zlib.Deflate.Proofs.DefaultInit
14open C Zlib.Deflate Zlib.Deflate.Spec
15open ZlibF.Spec.Public
16set_option autoImplicit false
17
18/-- The default entry normalizes only its caller-supplied compression level. -/
19def levelValue (level : Int32) : Int32 := if level == Z_DEFAULT_COMPRESSION then 6 else level
20
21/-- The actual allocation suffix at the default method, window, memory and
22strategy. Constant arithmetic is discharged by the whole-source equality.
23All allocations, stores and cleanup calls retain their source order. -/
24def allocate (strm : ZStreamPtr) (level : Int32) : M Int32 := do
25  zalloc_default strm
26  let s ← allocDeflateState
27  if s == none then return Z_MEM_ERROR
28  stDeflateState s DeflateState.zeroed
29  zwr strm (fun z => { z with state := StateRef.ofDeflateState s })
30  wr s (fun d => { d with
31    strm := strm, status := INIT_STATE, wrap := 1,
32    w_bits := 15, w_size := 32768, w_mask := 32767,
33    hash_bits := 15, hash_size := 32768, hash_mask := 32767, hash_shift := 5 })
34  let window ← ZALLOC_bytes strm 32768 2
35  wr s (fun d => { d with window })
36  let prev ← ZALLOC_words strm 32768
37  wr s (fun d => { d with prev })
38  let head ← ZALLOC_words strm 32768
39  wr s (fun d => { d with head })
40  wr s (fun d => { d with high_water := 0, lit_bufsize := 16384 })
41  let pending_buf ← ZALLOC_bytes strm 16384 4
42  wr s (fun d => { d with pending_buf, pending_buf_size := 65536 })
43  if window == .null || prev == .null || head == .null || pending_buf == .null then
44    wr s (fun d => { d with status := FINISH_STATE })
45    let m ← ERR_MSG Z_MEM_ERROR
46    zwr strm (fun z => { z with msg := m })
47    let _ ← deflateEnd strm
48    return Z_MEM_ERROR
49  let sym_buf ← padd pending_buf 16384
50  wr s (fun d => { d with sym_buf, sym_end := 49149 })
51  wr s (fun d => { d with level, strategy := 0, «method» := 8 })
52  deflateReset strm
53
54/-- `int deflateInit_(z_streamp strm, int level, const char *version, int stream_size)`.
55Source equality specializes the translated call, without requiring the
56universal deflateInit2_ theorem. The arbitrary level and refusal order remain. -/
57theorem source_eq (strm : ZStreamPtr) (level : Int32) (version : BPtr) (size : Int32) :
58    deflateInit_ strm level version size = (do
59      if version == .null then return Z_VERSION_ERROR
60      if (← load8 version) != 49 || size != sizeof_z_stream then return Z_VERSION_ERROR
61      if strm == none then return Z_STREAM_ERROR
62      zwr strm (fun z => { z with msg := .null })
63      if (← zrd strm (·.zalloc)) == FnPtr.null then
64        zwr strm (fun z => { z with zalloc := FnPtr.fn "zcalloc", «opaque» := .null })
65      if (← zrd strm (·.zfree)) == FnPtr.null then
66        zwr strm (fun z => { z with zfree := FnPtr.fn "zcfree" })
67      if levelValue level < 0 || levelValue level > 9 then return Z_STREAM_ERROR
68      allocate strm (levelValue level)) := by
69  by_cases hd : level = Z_DEFAULT_COMPRESSION
70  all_goals unfold deflateInit_ deflateInit2_ allocate levelValue
71  all_goals simp [hd, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, MAX_MEM_LEVEL,
72    Z_FIXED, MIN_MATCH_u, iadd, ishl, chk32, M_bind_assoc, M_pure_bind]
73  all_goals rfl
74
75/-- The default allocator check reads the actual stream record. -/
76theorem allocator_run {h : Heap} {r : ZStreamRef} {z : ZStream}
77    (hz : r.get h = some z) (ha : z.zalloc = .fn "zcalloc") :
78    zalloc_default (some r) h = .ok ((), h) := by
79  simp [zalloc_default, bind_app, ldZ_eq, hz, ha]
80
81/-- Both nullable allocator fields are prepared exactly as specified. -/
82theorem prepared_allocators {z : ZStream} (ha : DefaultOrNull z) :
83    (preparedStream z).zalloc = .fn "zcalloc" ∧ (preparedStream z).zfree = .fn "zcfree" := by
84  obtain ⟨hza, hzf⟩ := ha
85  rcases hza with hza | hza <;> rcases hzf with hzf | hzf <;>
86    simp [preparedStream, hza, hzf]
87
88/-- The deflate version check dereferences the actual version pointer. -/
89theorem version_load {h : Heap} {v : BPtr} {byte : UInt8}
90    (hv : VersionValue h v (some byte)) : v ≠ .null ∧ load8 v h = .ok (byte, h) := by
91  rcases hv with ⟨_, hn⟩ | ⟨b, hb, hbytes⟩
92  · cases hn
93  · cases hb
94    rcases hbytes with ⟨_, hn, _⟩ | ⟨ref, off, a, rfl, hg, hfit, hlist⟩
95    · cases hn
96    · have hi : off < a.size := by omega
97      have he : a[off]? = some byte := by
98        have hh := congrArg (fun l : List UInt8 => l[0]?) hlist
99        simpa [List.getElem?_take, List.getElem?_drop] using hh.symm
100      have hbyte : a[off] = byte := by
101        rw [Array.getElem?_eq_getElem hi] at he
102        exact Option.some.inj he
103      refine ⟨by simp, ?_⟩
104      have hr := Ptr.load_ok hg hi
105      simpa only [OkOn, load8, hbyte] using hr
106
107/-- Version and size refusal occurs before any stream access or allocation. -/
108theorem version_refusal (level : Int32) :
109    ∀ h p version head size, VersionValue h version head →
110      (head ≠ some 49 ∨ size ≠ 112) →
111      C.run (deflateInit_ p level version size) h = .ok (Z_VERSION_ERROR, h) := by
112  intro h p version head size hv hbad
113  rw [C.run, source_eq]
114  cases head with
115  | none =>
116    rcases hv with ⟨rfl, _⟩ | ⟨b, hb, _⟩
117    · simp
118    · cases hb
119  | some byte =>
120    obtain ⟨hn, read⟩ := version_load hv
121    by_cases hb : byte = 49
122    · subst byte
123      have hs : size ≠ 112 := by simpa using hbad
124      simp [hn, bind_app, read, sizeof_z_stream, hs]
125    · simp [hn, bind_app, read, hb]
126
127/-- The null stream is rejected after the successful version read. -/
128theorem null_stream (level : Int32) :
129    ∀ h version, VersionValue h version (some 49) →
130      C.run (deflateInit_ none level version 112) h = .ok (Z_STREAM_ERROR, h) := by
131  intro h version hv
132  obtain ⟨hn, read⟩ := version_load hv
133  rw [C.run, source_eq]
134  simp [hn, bind_app, read, sizeof_z_stream]
135
136/-- After the successful version read, the actual prefix prepares the
137stream and checks the arbitrary level before entering allocation. -/
138theorem entry_run {h : Heap} {r : ZStreamRef} {z : ZStream} {version : BPtr}
139    (hz : r.get h = some z) (hv : VersionValue h version (some 49)) (level : Int32) :
140    deflateInit_ (some r) level version 112 h =
141      (if levelValue level < 0 || levelValue level > 9 then
142        .ok (Z_STREAM_ERROR, r.put h (preparedStream z))
143      else allocate (some r) (levelValue level) (r.put h (preparedStream z))) := by
144  obtain ⟨hn, read⟩ := version_load hv
145  rw [source_eq]
146  by_cases hza : z.zalloc = .null <;> by_cases hzf : z.zfree = .null <;>
147    by_cases bad : levelValue level < 0 ∨ 9 < levelValue level
148  all_goals simp [hn, bind_app, pure_app, read, sizeof_z_stream, zwr_eq, zrd_eq, hz,
149    ZStreamRef.get_put_same hz, ZStreamRef.put_put, preparedStream, hza, hzf, bad]
150
151/-- Failure of the first allocation returns before any state is published. -/
152theorem allocate_state_fail {h : Heap} {r : ZStreamRef} {z : ZStream}
153    (hz : r.get h = some z) (ha : z.zalloc = .fn "zcalloc")
154    (hf : h.allocOk h.nalloc = false) (level : Int32) :
155    allocate (some r) level h = .ok (Z_MEM_ERROR, { h with nalloc := h.nalloc + 1 }) := by
156  unfold allocate
157  rw [bind_app, allocator_run hz ha]
158  simp only []
159  rw [bind_app, allocDeflateState_none (by rw [hf]; decide)]
160  rfl
161
162/-- The actual byte-buffer allocator, including arbitrary allocation failure. -/
163theorem bytes_run {h : Heap} {r : ZStreamRef} {z : ZStream}
164    (hf : Fresh h) (hz : r.get h = some z) (ha : z.zalloc = .fn "zcalloc")
165    (items size : UInt32) :
166    ZALLOC_bytes (some r) items size h = .ok (bytePtr h, byteResult h (items * size).toNat) := by
167  unfold ZALLOC_bytes
168  rw [bind_app, allocator_run hz ha]
169  simp only []
170  simp only [bind_app, ldZ_eq, hz]
171  exact byte_alloc_run hf _
172
173/-- The actual word-buffer allocator retains its unsigned byte product. -/
174theorem words_run {h : Heap} {r : ZStreamRef} {z : ZStream}
175    (hf : Fresh h) (hz : r.get h = some z) (ha : z.zalloc = .fn "zcalloc") (items : UInt32) :
176    ZALLOC_words (some r) items h = .ok (wordPtr h, wordResult h ((items * 2).toNat / 2)) := by
177  unfold ZALLOC_words
178  rw [bind_app, allocator_run hz ha]
179  exact word_alloc_run hf _
180
181/-- The four actual buffer allocations and their intervening stores. -/
182def buffers (strm : ZStreamPtr) (s : DeflateStatePtr) : M (BPtr × WPtr × WPtr × BPtr) := do
183  let window ← ZALLOC_bytes strm 32768 2
184  wr s (fun d => { d with window })
185  let prev ← ZALLOC_words strm 32768
186  wr s (fun d => { d with prev })
187  let head ← ZALLOC_words strm 32768
188  wr s (fun d => { d with head })
189  wr s (fun d => { d with high_water := 0, lit_bufsize := 16384 })
190  let pending_buf ← ZALLOC_bytes strm 16384 4
191  wr s (fun d => { d with pending_buf, pending_buf_size := 65536 })
192  pure (window, prev, head, pending_buf)
193
194def windowHeap (h : Heap) : Heap := byteResult h 65536
195def prevHeap (h : Heap) : Heap := wordResult (windowHeap h) 32768
196def headHeap (h : Heap) : Heap := wordResult (prevHeap h) 32768
197def buffersHeap (h : Heap) : Heap := byteResult (headHeap h) 65536
198
199def bufferPointers (h : Heap) : BPtr × WPtr × WPtr × BPtr :=
200  (bytePtr h, wordPtr (windowHeap h), wordPtr (prevHeap h), bytePtr (headHeap h))
201
202def bufferState (h : Heap) (d : DeflateState) : DeflateState :=
203  { d with
204    window := bytePtr h, prev := wordPtr (windowHeap h), head := wordPtr (prevHeap h),
205    high_water := 0, lit_bufsize := 16384,
206    pending_buf := bytePtr (headHeap h), pending_buf_size := 65536 }
207
208/-- Each of the four buffer requests executes even if an earlier one fails.
209The theorem retains the exact oracle-dependent pointers and heap, before
210the cleanup decision. No initialized-state invariant is assumed. -/
211theorem buffers_run {h : Heap} {r : ZStreamRef} {z : ZStream} {ds : Nat} {d : DeflateState}
212    (hf : Fresh h) (hz : r.get h = some z) (ha : z.zalloc = .fn "zcalloc")
213    (hs : h.dstates ds = some d) (hds : ds < h.nextBlk) :
214    buffers (some r) (some (.tab ds)) h =
215      .ok (bufferPointers h, setD (buffersHeap h) ds (bufferState h d)) := by
216  let d1 := { d with window := bytePtr h }
217  let H1 := setD (windowHeap h) ds d1
218  let d2 := { d1 with prev := wordPtr (windowHeap h) }
219  let H2 := setD (prevHeap h) ds d2
220  let d3 := { d2 with head := wordPtr (prevHeap h) }
221  let d4 := { d3 with high_water := 0, lit_bufsize := 16384 }
222  let H4 := setD (headHeap h) ds d4
223  have fW := fresh_byteResult hf 65536
224  have fP := fresh_wordResult fW 32768
225  have fH := fresh_wordResult fP 32768
226  have pW := byteResult_next h 65536
227  have pP := wordResult_next (windowHeap h) 32768
228  have pH := wordResult_next (prevHeap h) 32768
229  have hf1 : Fresh H1 := fresh_setD_below fW ds (by dsimp only [windowHeap] at *; omega) d1
230  have hf2 : Fresh H2 := fresh_setD_below fP ds (by dsimp only [prevHeap, windowHeap] at *; omega) d2
231  have hf4 : Fresh H4 := fresh_setD_below fH ds
232    (by dsimp only [headHeap, prevHeap, windowHeap] at *; omega) d4
233  have runW := bytes_run hf hz ha 32768 2
234  have runP := words_run hf1 (r := r) (z := z) (by simpa [H1, windowHeap] using hz) ha 32768
235  have runH := words_run hf2 (r := r) (z := z) (by simpa [H2, prevHeap, windowHeap] using hz) ha 32768
236  have runB := bytes_run hf4 (r := r) (z := z) (by simpa [H4, headHeap, prevHeap, windowHeap] using hz) ha 16384 4
237  change ZALLOC_bytes (some r) 32768 2 h = .ok (bytePtr h, windowHeap h) at runW
238  simp only [show ((32768 : UInt32) * 2).toNat / 2 = 32768 from by decide +kernel] at runP runH
239  simp only [show ((16384 : UInt32) * 4).toNat = 65536 from by decide +kernel] at runB
240  simp only [H1, H2, H4, prevHeap, headHeap, buffersHeap, windowHeap, wordPtr_setD,
241    bytePtr_setD, wordResult_setD, byteResult_setD] at runP runH runB
242  dsimp only [d1, d2, d3, d4, prevHeap, headHeap, windowHeap] at runP runH runB
243  unfold buffers
244  rw [bind_app, runW]
245  simp only [bind_app, wrD_eq, windowHeap, byteResult_dstates, hs, d1, d2, d3, d4]
246  rw [runP]
247  simp only [bind_app, wrD_eq, setD_dstates_same, setD_setD, d1, d2, d3, d4]
248  rw [runH]
249  simp only [bind_app, wrD_eq, setD_dstates_same, setD_setD, d1, d2, d3, d4]
250  rw [runB]
251  simp only [bind_app, wrD_eq, setD_dstates_same, setD_setD, pure_app]
252  rfl
253
254/-- The exact state fields written before the four buffer allocations. -/
255def baseState (r : ZStreamRef) : DeflateState :=
256  { DeflateState.zeroed with
257    strm := some r, status := INIT_STATE, wrap := 1,
258    w_bits := 15, w_size := 32768, w_mask := 32767,
259    hash_bits := 15, hash_size := 32768, hash_mask := 32767, hash_shift := 5 }
260
261def stateStream (z : ZStream) (ds : Nat) : ZStream := { z with state := some (.deflate ds) }
262
263def publishedHeap (h : Heap) (r : ZStreamRef) (z : ZStream) : Heap :=
264  stateHeap (r.put h (stateStream z h.nextBlk)) (baseState r)
265
266/-- The actual final decision after all four buffer requests. -/
267def finish (strm : ZStreamPtr) (s : DeflateStatePtr) (level : Int32)
268    (ps : BPtr × WPtr × WPtr × BPtr) : M Int32 := do
269  let (window, prev, head, pending_buf) := ps
270  if window == .null || prev == .null || head == .null || pending_buf == .null then
271    wr s (fun d => { d with status := FINISH_STATE })
272    let m ← ERR_MSG Z_MEM_ERROR
273    zwr strm (fun z => { z with msg := m })
274    let _ ← deflateEnd strm
275    return Z_MEM_ERROR
276  let sym_buf ← padd pending_buf 16384
277  wr s (fun d => { d with sym_buf, sym_end := 49149 })
278  wr s (fun d => { d with level, strategy := 0, «method» := 8 })
279  deflateReset strm
280
281/-- Naming allocation and cleanup cut points preserves the actual suffix. -/
282theorem allocate_eq (strm : ZStreamPtr) (level : Int32) : allocate strm level = (do
283    zalloc_default strm
284    let s ← allocDeflateState
285    if s == none then return Z_MEM_ERROR
286    stDeflateState s DeflateState.zeroed
287    zwr strm (fun z => { z with state := StateRef.ofDeflateState s })
288    wr s (fun d => { d with
289      strm := strm, status := INIT_STATE, wrap := 1,
290      w_bits := 15, w_size := 32768, w_mask := 32767,
291      hash_bits := 15, hash_size := 32768, hash_mask := 32767, hash_shift := 5 })
292    let ps ← buffers strm s
293    finish strm s level ps) := by
294  unfold allocate buffers finish
295  simp only [M_bind_assoc, M_pure_bind]
296
297/-- Actual state allocation, zeroing and publication, followed by all four
298buffer requests. Its result is the real cleanup/success cut point for
299every four-buffer allocation oracle. -/
300theorem allocate_to_finish {h : Heap} {r : ZStreamRef} {z : ZStream}
301    (hf : Fresh h) (hz : r.get h = some z) (ha : z.zalloc = .fn "zcalloc")
302    (ho : h.allocOk h.nalloc = true) (level : Int32) :
303    allocate (some r) level h =
304      finish (some r) (some (.tab h.nextBlk)) level (bufferPointers (publishedHeap h r z))
305        (setD (buffersHeap (publishedHeap h r z)) h.nextBlk
306          (bufferState (publishedHeap h r z) (baseState r))) := by
307  have hfP : Fresh (publishedHeap h r z) :=
308    fresh_stateHeap ((shape_put hz _).fresh (by simp) hf) _
309  have hsP : (publishedHeap h r z).dstates h.nextBlk = some (baseState r) := by
310    simp [publishedHeap, stateHeap]
311  have hzP : r.get (publishedHeap h r z) = some (stateStream z h.nextBlk) := by
312    simp [publishedHeap, ZStreamRef.get_put_same hz]
313  have hbuffer := buffers_run hfP hzP (by simpa [stateStream] using ha) hsP
314    (by simp [publishedHeap, stateHeap])
315  rw [allocate_eq]
316  rw [bind_app, allocator_run hz ha]
317  simp only []
318  have runS : allocDeflateState h = .ok (some (.tab h.nextBlk),
319      stateHeap h (DeflateState.garbage (h.garbage h.nalloc))) := allocDeflateState_some ho
320  rw [bind_app, runS]
321  simp [bind_app, stD_eq, pure_app, ZStreamRef.put_dstates, stateHeap_dstates_same,
322    zwr_eq, get_stateHeap, ZStreamRef.get_put_same hz, wrD_eq, upd_upd,
323    put_stateHeap, stateHeap_setD, hz, StateRef.ofDeflateState]
324  change (do let ps ← buffers (some r) (some (.tab h.nextBlk))
325             finish (some r) (some (.tab h.nextBlk)) level ps) (publishedHeap h r z) = _
326  rw [bind_app, hbuffer]
327
328end Zlib.Deflate.Proofs.DefaultInit
ZLIB × LEAN

Global contents

READING NOWdeflate.c.init.default.lean