REFERENCE / ZLIB × LEAN
LibcTables.lean
Source snapshot ·
ea76a11c26d7d686 · 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.Runtime.Tables
2
3/-!
4# `malloc`, `free` and `memcpy` of every struct kind (GENERATED, do not edit)
5
6`allocK` and `freeK` are `malloc(sizeof(K))` and `free` through the default allocator, `copyK dst src` is the
7`memcpy` of a whole record. They model the C library (see `Libc.lean` and `docs/trusted-base.md`); the loads and
8stores of the records are in `Tables.lean`.
9-/
10
11namespace C
12
13/-- `malloc(sizeof(z_stream))` through the default allocator: a fresh live record with arbitrary integers and
14null pointers (a documented gap: C leaves them indeterminate, see `docs/trusted-base.md`), or null when the
15failure oracle says so. It is a fault (not a C behaviour) if the block number `nextBlk` is already in use:
16the heap is then not `Fresh`, and a theorem about allocation carries `Fresh`. -/
17def allocZStream : M ZStreamPtr := fun h =>
18 if h.allocOk h.nalloc then
19 if h.slotUsed h.nextBlk then .error (.ub "allocation: the block number is in use (the heap is not Fresh)")
20 else .ok (some (.tab h.nextBlk), { h with streams := upd h.streams h.nextBlk (some (ZStream.garbage (h.garbage h.nalloc))), nextBlk := h.nextBlk + 1, nalloc := h.nalloc + 1 })
21 else .ok (none, { h with nalloc := h.nalloc + 1 })
22
23/-- Alias of `allocZStream`. -/
24abbrev allocZStreamChk := allocZStream
25
26theorem allocZStream_some {h : Heap} (hok : h.allocOk h.nalloc = true)
27 (hs : h.slotUsed h.nextBlk = false := by fresh_slot) :
28 allocZStream h = .ok (some (.tab h.nextBlk), { h with streams := upd h.streams h.nextBlk (some (ZStream.garbage (h.garbage h.nalloc))), nextBlk := h.nextBlk + 1, nalloc := h.nalloc + 1 }) := by simp [allocZStream, hok, hs]
29
30theorem allocZStream_none {h : Heap} (hok : ¬ h.allocOk h.nalloc = true) :
31 allocZStream h = .ok (none, { h with nalloc := h.nalloc + 1 }) := by simp [allocZStream, hok]
32
33/-- `free(p)` for a `z_stream *`: a no-op for null; faults for a block that is not live (double free) and for a
34pointer that was not returned by the allocator. -/
35def freeZStream (p : ZStreamPtr) : M Unit := fun h =>
36 match p with
37 | none => .ok ((), h)
38 | some (.tab i) => match h.streams i with
39 | some _ => .ok ((), { h with streams := upd h.streams i none })
40 | none => .error (.ub "free of a freed or invalid pointer (z_stream)")
41 | some _ => .error (.ub "free of a pointer that was not allocated (z_stream)")
42
43theorem freeZStream_null {h : Heap} : freeZStream none h = .ok ((), h) := rfl
44
45/-- `*dst = *src` for two `z_stream *` (`zmemcpy(dst, src, sizeof *dst)`): a whole-record copy. Faults if either pointer
46is null, dangling or the destination read-only, and if both denote the same object (`memcpy` with overlapping
47ranges is undefined; the `z_stream` objects of the heap do not contain one another). -/
48def copyZStream (dst src : ZStreamPtr) : M Unit := fun h =>
49 match dst, src with
50 | some d, some s =>
51 if d = s then .error (.ub "memcpy of a z_stream onto itself (overlapping ranges)")
52 else (ldZStream (some s) >>= fun v => stZStream (some d) v) h
53 | _, _ => .error (.ub "null dereference (z_stream)")
54
55theorem freeZStream_tab {h : Heap} {i : Nat} {v : ZStream} (e : h.streams i = some v) :
56 freeZStream (some (.tab i)) h = .ok ((), { h with streams := upd h.streams i none }) := by simp [freeZStream, e]
57
58/-- `malloc(sizeof(gz_header))` through the default allocator: a fresh live record with arbitrary integers and
59null pointers (a documented gap: C leaves them indeterminate, see `docs/trusted-base.md`), or null when the
60failure oracle says so. It is a fault (not a C behaviour) if the block number `nextBlk` is already in use:
61the heap is then not `Fresh`, and a theorem about allocation carries `Fresh`. -/
62def allocGzHeader : M GzHeaderPtr := fun h =>
63 if h.allocOk h.nalloc then
64 if h.slotUsed h.nextBlk then .error (.ub "allocation: the block number is in use (the heap is not Fresh)")
65 else .ok (some (.tab h.nextBlk), { h with gzheaders := upd h.gzheaders h.nextBlk (some (GzHeader.garbage (h.garbage h.nalloc))), nextBlk := h.nextBlk + 1, nalloc := h.nalloc + 1 })
66 else .ok (none, { h with nalloc := h.nalloc + 1 })
67
68/-- Alias of `allocGzHeader`. -/
69abbrev allocGzHeaderChk := allocGzHeader
70
71theorem allocGzHeader_some {h : Heap} (hok : h.allocOk h.nalloc = true)
72 (hs : h.slotUsed h.nextBlk = false := by fresh_slot) :
73 allocGzHeader h = .ok (some (.tab h.nextBlk), { h with gzheaders := upd h.gzheaders h.nextBlk (some (GzHeader.garbage (h.garbage h.nalloc))), nextBlk := h.nextBlk + 1, nalloc := h.nalloc + 1 }) := by simp [allocGzHeader, hok, hs]
74
75theorem allocGzHeader_none {h : Heap} (hok : ¬ h.allocOk h.nalloc = true) :
76 allocGzHeader h = .ok (none, { h with nalloc := h.nalloc + 1 }) := by simp [allocGzHeader, hok]
77
78/-- `free(p)` for a `gz_header *`: a no-op for null; faults for a block that is not live (double free) and for a
79pointer that was not returned by the allocator. -/
80def freeGzHeader (p : GzHeaderPtr) : M Unit := fun h =>
81 match p with
82 | none => .ok ((), h)
83 | some (.tab i) => match h.gzheaders i with
84 | some _ => .ok ((), { h with gzheaders := upd h.gzheaders i none })
85 | none => .error (.ub "free of a freed or invalid pointer (gz_header)")
86
87theorem freeGzHeader_null {h : Heap} : freeGzHeader none h = .ok ((), h) := rfl
88
89/-- `*dst = *src` for two `gz_header *` (`zmemcpy(dst, src, sizeof *dst)`): a whole-record copy. Faults if either pointer
90is null, dangling or the destination read-only, and if both denote the same object (`memcpy` with overlapping
91ranges is undefined; the `gz_header` objects of the heap do not contain one another). -/
92def copyGzHeader (dst src : GzHeaderPtr) : M Unit := fun h =>
93 match dst, src with
94 | some d, some s =>
95 if d = s then .error (.ub "memcpy of a gz_header onto itself (overlapping ranges)")
96 else (ldGzHeader (some s) >>= fun v => stGzHeader (some d) v) h
97 | _, _ => .error (.ub "null dereference (gz_header)")
98
99theorem freeGzHeader_tab {h : Heap} {i : Nat} {v : GzHeader} (e : h.gzheaders i = some v) :
100 freeGzHeader (some (.tab i)) h = .ok ((), { h with gzheaders := upd h.gzheaders i none }) := by simp [freeGzHeader, e]
101
102/-- `malloc(sizeof(deflate_state))` through the default allocator: a fresh live record with arbitrary integers and
103null pointers (a documented gap: C leaves them indeterminate, see `docs/trusted-base.md`), or null when the
104failure oracle says so. It is a fault (not a C behaviour) if the block number `nextBlk` is already in use:
105the heap is then not `Fresh`, and a theorem about allocation carries `Fresh`. -/
106def allocDeflateState : M DeflateStatePtr := fun h =>
107 if h.allocOk h.nalloc then
108 if h.slotUsed h.nextBlk then .error (.ub "allocation: the block number is in use (the heap is not Fresh)")
109 else .ok (some (.tab h.nextBlk), { h with dstates := upd h.dstates h.nextBlk (some (DeflateState.garbage (h.garbage h.nalloc))), nextBlk := h.nextBlk + 1, nalloc := h.nalloc + 1 })
110 else .ok (none, { h with nalloc := h.nalloc + 1 })
111
112/-- Alias of `allocDeflateState`. -/
113abbrev allocDeflateStateChk := allocDeflateState
114
115theorem allocDeflateState_some {h : Heap} (hok : h.allocOk h.nalloc = true)
116 (hs : h.slotUsed h.nextBlk = false := by fresh_slot) :
117 allocDeflateState h = .ok (some (.tab h.nextBlk), { h with dstates := upd h.dstates h.nextBlk (some (DeflateState.garbage (h.garbage h.nalloc))), nextBlk := h.nextBlk + 1, nalloc := h.nalloc + 1 }) := by simp [allocDeflateState, hok, hs]
118
119theorem allocDeflateState_none {h : Heap} (hok : ¬ h.allocOk h.nalloc = true) :
120 allocDeflateState h = .ok (none, { h with nalloc := h.nalloc + 1 }) := by simp [allocDeflateState, hok]
121
122/-- `free(p)` for a `deflate_state *`: a no-op for null; faults for a block that is not live (double free) and for a
123pointer that was not returned by the allocator. -/
124def freeDeflateState (p : DeflateStatePtr) : M Unit := fun h =>
125 match p with
126 | none => .ok ((), h)
127 | some (.tab i) => match h.dstates i with
128 | some _ => .ok ((), { h with dstates := upd h.dstates i none })
129 | none => .error (.ub "free of a freed or invalid pointer (deflate_state)")
130
131theorem freeDeflateState_null {h : Heap} : freeDeflateState none h = .ok ((), h) := rfl
132
133/-- `*dst = *src` for two `deflate_state *` (`zmemcpy(dst, src, sizeof *dst)`): a whole-record copy. Faults if either pointer
134is null, dangling or the destination read-only, and if both denote the same object (`memcpy` with overlapping
135ranges is undefined; the `deflate_state` objects of the heap do not contain one another). -/
136def copyDeflateState (dst src : DeflateStatePtr) : M Unit := fun h =>
137 match dst, src with
138 | some d, some s =>
139 if d = s then .error (.ub "memcpy of a deflate_state onto itself (overlapping ranges)")
140 else (ldDeflateState (some s) >>= fun v => stDeflateState (some d) v) h
141 | _, _ => .error (.ub "null dereference (deflate_state)")
142
143theorem freeDeflateState_tab {h : Heap} {i : Nat} {v : DeflateState} (e : h.dstates i = some v) :
144 freeDeflateState (some (.tab i)) h = .ok ((), { h with dstates := upd h.dstates i none }) := by simp [freeDeflateState, e]
145
146/-- `malloc(sizeof(inflate_state))` through the default allocator: a fresh live record with arbitrary integers and
147null pointers (a documented gap: C leaves them indeterminate, see `docs/trusted-base.md`), or null when the
148failure oracle says so. It is a fault (not a C behaviour) if the block number `nextBlk` is already in use:
149the heap is then not `Fresh`, and a theorem about allocation carries `Fresh`. -/
150def allocInflateState : M InflateStatePtr := fun h =>
151 if h.allocOk h.nalloc then
152 if h.slotUsed h.nextBlk then .error (.ub "allocation: the block number is in use (the heap is not Fresh)")
153 else .ok (some (.tab h.nextBlk), { h with istates := upd h.istates h.nextBlk (some (InflateState.garbage (h.garbage h.nalloc))), nextBlk := h.nextBlk + 1, nalloc := h.nalloc + 1 })
154 else .ok (none, { h with nalloc := h.nalloc + 1 })
155
156/-- Alias of `allocInflateState`. -/
157abbrev allocInflateStateChk := allocInflateState
158
159theorem allocInflateState_some {h : Heap} (hok : h.allocOk h.nalloc = true)
160 (hs : h.slotUsed h.nextBlk = false := by fresh_slot) :
161 allocInflateState h = .ok (some (.tab h.nextBlk), { h with istates := upd h.istates h.nextBlk (some (InflateState.garbage (h.garbage h.nalloc))), nextBlk := h.nextBlk + 1, nalloc := h.nalloc + 1 }) := by simp [allocInflateState, hok, hs]
162
163theorem allocInflateState_none {h : Heap} (hok : ¬ h.allocOk h.nalloc = true) :
164 allocInflateState h = .ok (none, { h with nalloc := h.nalloc + 1 }) := by simp [allocInflateState, hok]
165
166/-- `free(p)` for a `inflate_state *`: a no-op for null; faults for a block that is not live (double free) and for a
167pointer that was not returned by the allocator. -/
168def freeInflateState (p : InflateStatePtr) : M Unit := fun h =>
169 match p with
170 | none => .ok ((), h)
171 | some (.tab i) => match h.istates i with
172 | some _ => .ok ((), { h with istates := upd h.istates i none })
173 | none => .error (.ub "free of a freed or invalid pointer (inflate_state)")
174
175theorem freeInflateState_null {h : Heap} : freeInflateState none h = .ok ((), h) := rfl
176
177/-- `*dst = *src` for two `inflate_state *` (`zmemcpy(dst, src, sizeof *dst)`): a whole-record copy. Faults if either pointer
178is null, dangling or the destination read-only, and if both denote the same object (`memcpy` with overlapping
179ranges is undefined; the `inflate_state` objects of the heap do not contain one another). -/
180def copyInflateState (dst src : InflateStatePtr) : M Unit := fun h =>
181 match dst, src with
182 | some d, some s =>
183 if d = s then .error (.ub "memcpy of a inflate_state onto itself (overlapping ranges)")
184 else (ldInflateState (some s) >>= fun v => stInflateState (some d) v) h
185 | _, _ => .error (.ub "null dereference (inflate_state)")
186
187theorem freeInflateState_tab {h : Heap} {i : Nat} {v : InflateState} (e : h.istates i = some v) :
188 freeInflateState (some (.tab i)) h = .ok ((), { h with istates := upd h.istates i none }) := by simp [freeInflateState, e]
189
190/-- `malloc(sizeof(gz_state))` through the default allocator: a fresh live record with arbitrary integers and
191null pointers (a documented gap: C leaves them indeterminate, see `docs/trusted-base.md`), or null when the
192failure oracle says so. It is a fault (not a C behaviour) if the block number `nextBlk` is already in use:
193the heap is then not `Fresh`, and a theorem about allocation carries `Fresh`. -/
194def allocGzState : M GzStatePtr := fun h =>
195 if h.allocOk h.nalloc then
196 if h.slotUsed h.nextBlk then .error (.ub "allocation: the block number is in use (the heap is not Fresh)")
197 else .ok (some (.tab h.nextBlk), { h with gzstates := upd h.gzstates h.nextBlk (some (GzState.garbage (h.garbage h.nalloc))), nextBlk := h.nextBlk + 1, nalloc := h.nalloc + 1 })
198 else .ok (none, { h with nalloc := h.nalloc + 1 })
199
200/-- Alias of `allocGzState`. -/
201abbrev allocGzStateChk := allocGzState
202
203theorem allocGzState_some {h : Heap} (hok : h.allocOk h.nalloc = true)
204 (hs : h.slotUsed h.nextBlk = false := by fresh_slot) :
205 allocGzState h = .ok (some (.tab h.nextBlk), { h with gzstates := upd h.gzstates h.nextBlk (some (GzState.garbage (h.garbage h.nalloc))), nextBlk := h.nextBlk + 1, nalloc := h.nalloc + 1 }) := by simp [allocGzState, hok, hs]
206
207theorem allocGzState_none {h : Heap} (hok : ¬ h.allocOk h.nalloc = true) :
208 allocGzState h = .ok (none, { h with nalloc := h.nalloc + 1 }) := by simp [allocGzState, hok]
209
210/-- `free(p)` for a `gz_state *`: a no-op for null; faults for a block that is not live (double free) and for a
211pointer that was not returned by the allocator. -/
212def freeGzState (p : GzStatePtr) : M Unit := fun h =>
213 match p with
214 | none => .ok ((), h)
215 | some (.tab i) => match h.gzstates i with
216 | some _ => .ok ((), { h with gzstates := upd h.gzstates i none })
217 | none => .error (.ub "free of a freed or invalid pointer (gz_state)")
218
219theorem freeGzState_null {h : Heap} : freeGzState none h = .ok ((), h) := rfl
220
221/-- `*dst = *src` for two `gz_state *` (`zmemcpy(dst, src, sizeof *dst)`): a whole-record copy. Faults if either pointer
222is null, dangling or the destination read-only, and if both denote the same object (`memcpy` with overlapping
223ranges is undefined; the `gz_state` objects of the heap do not contain one another). -/
224def copyGzState (dst src : GzStatePtr) : M Unit := fun h =>
225 match dst, src with
226 | some d, some s =>
227 if d = s then .error (.ub "memcpy of a gz_state onto itself (overlapping ranges)")
228 else (ldGzState (some s) >>= fun v => stGzState (some d) v) h
229 | _, _ => .error (.ub "null dereference (gz_state)")
230
231theorem freeGzState_tab {h : Heap} {i : Nat} {v : GzState} (e : h.gzstates i = some v) :
232 freeGzState (some (.tab i)) h = .ok ((), { h with gzstates := upd h.gzstates i none }) := by simp [freeGzState, e]
233
234end C