Browse zlib specs (50 of 62)
Proofs / zlib / Earlier, longer properties
x_inflate_dict
Preset dictionaries of up to 64 KiB: a zlib stream asks for the dictionary and reports its Adler-32, a wrong one gives Z_DATA_ERROR, the right one decodes the data, back-references into the dictionary included; inflateGetDictionary returns the window (data up to 256 KiB).
- spec
- 219 lines of C
- with its headers
- 544 lines
- status
- Proved
- 50 of 62
On this page
The spec
The spec is the C program harness/x_inflate_dict.c, 219 lines, shown whole as it is in the repository at 37189f4. It includes harness/deflate_ref.h (170 lines) and harness/zlib_common.h (155 lines). Its first comment states the property in full, with every bound.
// Law inflate_dict: preset dictionaries (RFC 1950 FDICT; zlib.h inflateSetDictionary, inflateGetDictionary). ANY
// dictionary of dlen <= 2^16 bytes; a zlib stream with FDICT (ANY window size 2^wb, wb 8..15, ANY FLEVEL, the
// dictionary id = the Adler-32 of the dictionary) or a raw stream, built by the reference encoder of
// harness/deflate_ref.h (RFC 1951) from ANY sequence of stored blocks (ANY bytes) and fixed-Huffman blocks of ANY
// literals and back-references of ANY length 3..258 at ANY distance 1..min(dlen + bytes so far, 2^wb) -- reaching
// into the dictionary -- (a drawn reference out of range is not sent), the last block final. inflateInit2 with a
// windowBits that accepts it (zlib: wb, 0, 32 + wb; raw: -wb); for a raw stream inflateSetDictionary right after it;
// then inflate() calls with ANY flush value, ANY further amount of the input (an amount beyond the end offers the
// rest), ANY output space <= 2^20 bytes (objects of exactly avail_in and avail_out bytes), until Z_STREAM_END; when
// inflate returns Z_NEED_DICT the caller sets, at its choice, first a wrong dictionary (the right one with its first
// byte changed, or one zero byte when dlen = 0), then the right one. After every call inflateGetDictionary is asked
// for the length, then for the bytes into an object of exactly that length. Properties:
// - raw: inflateSetDictionary returns Z_OK;
// - zlib: inflate returns Z_NEED_DICT, with strm->adler = the Adler-32 of the dictionary, until the dictionary is
// set, and before producing anything; the wrong dictionary gives Z_DATA_ERROR, the right one Z_OK;
// - otherwise every call returns Z_OK, Z_BUF_ERROR or Z_STREAM_END; the bytes produced are the next bytes of the
// encoded data; at Z_STREAM_END all of it was produced and exactly the stream consumed;
// - once the dictionary is set, inflateGetDictionary's length is min(dlen + bytes produced, 2^wb) and its bytes are
// the last that many bytes of the dictionary followed by the bytes produced (the sliding window); except after
// the call that returns Z_STREAM_END on a zlib stream, whose output inflate does not add to the window (by design:
// inflate.c, updatewindow's comment and state CHECK; the window is not needed after the end).
// (Z_MEM_ERROR ends the run.) Bounds: dlen <= 2^16, data <= 2^18 bytes, stream <= 2^19 bytes.
#include "deflate_ref.h"
#define GP_DICT_MAX (1u << 16)
#define GP_DATA_MAX (1u << 18)
#define GP_STREAM_MAX (1u << 19)
#define GP_OUT_MAX (1u << 20)
// history byte k of (dict ++ data): k < dlen in the dictionary
static unsigned char hist(const unsigned char *dict, unsigned dlen, const unsigned char *data, unsigned k)
{
return k < dlen ? dict[k] : data[k - dlen];
}
int main(void)
{
const unsigned char wrap = nondet_u8(); // 0 raw, else zlib
const unsigned char flevel = nondet_u8();
const unsigned char isel = nondet_u8();
const unsigned char wsel = nondet_u8();
const unsigned wb = nondet_u32();
const unsigned dlen = nondet_u32();
gp_assume(wb >= 8 && wb <= 15);
gp_assume(dlen <= GP_DICT_MAX);
const int zlib = wrap != 0;
unsigned char *dict = malloc(dlen);
unsigned char *bad = malloc(dlen == 0 ? 1 : dlen);
unsigned char *data = malloc(GP_DATA_MAX);
unsigned char *src = malloc(GP_STREAM_MAX);
if (dict == NULL || bad == NULL || data == NULL || src == NULL)
return 0;
nondet_bytes(dict, dlen);
const unsigned blen = dlen == 0 ? 1 : dlen;
if (dlen == 0) {
bad[0] = 0;
} else {
bytes_copy(bad, dict, dlen);
bad[0] = (unsigned char) (dict[0] ^ 1);
}
const unsigned long dictid = ref_adler32(1, dict, dlen);
struct bw w;
w.buf = src;
w.len = 0;
w.nb = 0;
const unsigned maxd = 1u << wb;
if (zlib) {
const unsigned cmf = ((wb - 8) << 4) | 8;
const unsigned flg0 = ((unsigned) (flevel & 3) << 6) | 0x20;
const unsigned flg = flg0 + (31 - ((cmf << 8) + flg0) % 31) % 31;
bw_byte(&w, (unsigned char) cmf);
bw_byte(&w, (unsigned char) flg);
bw_byte(&w, (unsigned char) (dictid >> 24));
bw_byte(&w, (unsigned char) (dictid >> 16));
bw_byte(&w, (unsigned char) (dictid >> 8));
bw_byte(&w, (unsigned char) dictid);
}
unsigned n = 0;
for (;;) {
const unsigned char more = nondet_u8();
const unsigned char btype = nondet_u8();
const unsigned last = more == 0;
gp_assume(w.len + 8 <= GP_STREAM_MAX);
bw_bits(&w, last, 1);
if ((btype & 3) == 0) { // stored
const unsigned len = nondet_u32();
gp_assume(len <= 65535);
gp_assume(n + len <= GP_DATA_MAX);
bw_bits(&w, 0, 2);
bw_align(&w);
gp_assume(w.len + 4 + len <= GP_STREAM_MAX);
bw_byte(&w, (unsigned char) len);
bw_byte(&w, (unsigned char) (len >> 8));
bw_byte(&w, (unsigned char) ~len);
bw_byte(&w, (unsigned char) (~len >> 8));
nondet_bytes(data + n, len);
bytes_copy(src + w.len, data + n, len);
w.len += len;
n += len;
} else { // fixed Huffman codes
bw_bits(&w, 1, 2);
for (;;) {
const unsigned char kind = nondet_u8();
gp_assume(w.len + 8 <= GP_STREAM_MAX);
if (kind == 0)
break;
if (kind < 128) {
const unsigned char lit = nondet_u8();
gp_assume(n < GP_DATA_MAX);
data[n] = lit;
n++;
bw_fixed(&w, lit);
} else {
const unsigned len = nondet_u32();
const unsigned dist = nondet_u32();
if (len < 3 || len > 258 || dist < 1 || dist > dlen + n || dist > maxd)
continue;
gp_assume(n + len <= GP_DATA_MAX);
for (unsigned i = 0; i < len; ++i)
data[n + i] = hist(dict, dlen, data, dlen + n + i - dist);
n += len;
bw_fixed_match(&w, len, dist);
}
}
bw_fixed(&w, 256);
}
if (last)
break;
}
bw_align(&w);
gp_assume(w.len + 4 <= GP_STREAM_MAX);
if (zlib) {
const unsigned long a = ref_adler32(1, data, n);
bw_byte(&w, (unsigned char) (a >> 24));
bw_byte(&w, (unsigned char) (a >> 16));
bw_byte(&w, (unsigned char) (a >> 8));
bw_byte(&w, (unsigned char) a);
}
const unsigned slen = w.len;
const int iw = !zlib ? -(int) wb : isel < 85 ? (int) wb : isel < 170 ? 0 : 32 + (int) wb;
z_stream s;
stream_defaults(&s);
int r = inflateInit2(&s, iw);
if (r != Z_OK)
return 0;
int dict_set = 0;
if (!zlib) {
r = inflateSetDictionary(&s, dict, dlen);
if (r == Z_MEM_ERROR)
return 0;
gp_assert(r == Z_OK);
dict_set = 1;
}
unsigned pos = 0, lim = 0, opos = 0;
for (;;) {
const unsigned step = nondet_u32();
const unsigned aout = nondet_u32();
const int flush = (int) nondet_u32();
gp_assume(aout <= GP_OUT_MAX);
lim = step < slen - lim ? lim + step : slen;
const unsigned ain = lim - pos;
unsigned char *ib = exact_copy(src + pos, ain);
unsigned char *osnap;
unsigned char *ob = exact_space(aout, &osnap);
if (ib == NULL || ob == NULL)
return 0;
s.next_in = ib;
s.avail_in = ain;
s.next_out = ob;
s.avail_out = aout;
r = inflate(&s, flush);
if (r == Z_MEM_ERROR)
return 0;
const unsigned made = aout - s.avail_out;
pos += ain - s.avail_in;
if (r == Z_NEED_DICT) {
gp_assert(zlib && !dict_set);
gp_assert(made == 0 && opos == 0);
gp_assert(s.adler == dictid);
if (wsel == 0) {
r = inflateSetDictionary(&s, bad, blen);
gp_assert(r == Z_DATA_ERROR);
}
r = inflateSetDictionary(&s, dict, dlen);
if (r == Z_MEM_ERROR)
return 0;
gp_assert(r == Z_OK);
dict_set = 1;
} else {
gp_assert(r == Z_OK || r == Z_BUF_ERROR || r == Z_STREAM_END);
gp_assert(made <= n - opos);
gp_assert(bytes_same(ob, data + opos, made));
opos += made;
}
if (dict_set && (r != Z_STREAM_END || !zlib)) {
uInt dl = 0;
gp_assert(inflateGetDictionary(&s, Z_NULL, &dl) == Z_OK);
const unsigned long have = (unsigned long) dlen + opos;
gp_assert(dl == (have < maxd ? have : maxd));
unsigned char *gd = malloc(dl);
if (gd == NULL)
return 0;
gp_assert(inflateGetDictionary(&s, gd, Z_NULL) == Z_OK);
for (unsigned i = 0; i < dl; ++i)
gp_assert(gd[i] == hist(dict, dlen, data, (unsigned) (have - dl) + i));
free(gd);
}
free(ib);
free(ob);
free(osnap);
if (r == Z_STREAM_END)
break;
}
gp_assert(opos == n);
gp_assert(pos == slen);
inflateEnd(&s);
return 0;
}harness/deflate_ref.h, 170 lines
// A reference DEFLATE encoder (RFC 1951), written from the RFC alone, for the inflate laws that check decoded output
// (inflate_decode): a bit writer, stored blocks (3.2.4), fixed-Huffman blocks (3.2.6) and dynamic-Huffman blocks
// (3.2.7) with ANY valid code lengths, literals, and back-references (3.2.5).
//
// - Bits are packed starting with the least significant bit of each byte; data elements (lengths, extra bits) are
// written least significant bit first, Huffman codes most significant bit first (3.1.1);
// - canonical codes (3.2.2): bl_count[len] = the number of codes of each length, next_code[1] = 0,
// next_code[len] = (next_code[len - 1] + bl_count[len - 1]) << 1, then the symbols in increasing order get
// consecutive codes of their length;
// - a dynamic block: BFINAL, BTYPE = 10, HLIT = nlen - 257, HDIST = ndist - 1, HCLEN = 19 - 4 (all 19 code length
// code lengths, 3 bits each, in the order 16 17 18 0 8 7 9 6 10 5 11 4 12 3 13 2 14 1 15), then the nlen + ndist
// code lengths (one sequence) in the code length code: 0..15 literally, 16 = copy the previous length 3..6 times
// (2 extra bits), 17 = 3..10 zeros (3 extra bits), 18 = 11..138 zeros (7 extra bits), then the symbols.
// inflate accepts a dynamic block's codes when (inflate.c, inftrees.c): nlen <= 286, ndist <= 30; the code length
// code is complete; the literal/length code has a code for 256 and is complete or a single code of length 1; the
// distance code is complete, a single code of length 1, or empty. kraft() and code_ok() state these.
#ifndef ZLIB_HARNESS_DEFLATE_REF_H
#define ZLIB_HARNESS_DEFLATE_REF_H
#include "zlib_common.h"
struct bw { // a bit writer, least significant bit first (RFC 1951 3.1.1)
unsigned char *buf;
unsigned len; // complete bytes
unsigned nb; // bits in buf[len]
};
static void bw_bit(struct bw *w, unsigned b)
{
if (w->nb == 0)
w->buf[w->len] = 0;
w->buf[w->len] = (unsigned char) (w->buf[w->len] | ((b & 1) << w->nb));
w->nb++;
if (w->nb == 8) {
w->nb = 0;
w->len++;
}
}
static void bw_bits(struct bw *w, unsigned v, unsigned n) // a value, its least significant bit first
{
for (unsigned i = 0; i < n; ++i)
bw_bit(w, v >> i);
}
static void bw_code(struct bw *w, unsigned c, unsigned n) // a Huffman code, its most significant bit first
{
for (unsigned i = n; i > 0; --i)
bw_bit(w, c >> (i - 1));
}
static void bw_byte(struct bw *w, unsigned char b) // at a byte boundary
{
w->buf[w->len] = b;
w->len++;
}
static void bw_align(struct bw *w)
{
if (w->nb != 0) {
w->nb = 0;
w->len++;
}
}
// the fixed literal/length code (RFC 1951 3.2.6)
static void bw_fixed(struct bw *w, unsigned v)
{
if (v < 144)
bw_code(w, 0x30 + v, 8);
else if (v < 256)
bw_code(w, 0x190 + (v - 144), 9);
else if (v < 280)
bw_code(w, v - 256, 7);
else
bw_code(w, 0xc0 + (v - 280), 8);
}
// RFC 1951 3.2.5: length codes 257..285 and distance codes 0..29
static const unsigned short ref_lbase[29] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59,
67, 83, 99, 115, 131, 163, 195, 227, 258};
static const unsigned char ref_lext[29] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5,
5, 5, 5, 0};
static const unsigned short ref_dbase[30] = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513,
769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577};
static const unsigned char ref_dext[30] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10,
11, 11, 12, 12, 13, 13};
static unsigned len_code(unsigned len) // the length code (0..28 for symbols 257..285) of a length 3..258
{
unsigned i = 28;
if (len < 258) {
i = 0;
while (i + 1 < 28 && ref_lbase[i + 1] <= len)
i++;
}
return i;
}
static unsigned dist_code(unsigned dist) // the distance code of a distance 1..32768
{
unsigned j = 0;
while (j + 1 < 30 && ref_dbase[j + 1] <= dist)
j++;
return j;
}
static void bw_fixed_match(struct bw *w, unsigned len, unsigned dist)
{
const unsigned i = len_code(len), j = dist_code(dist);
bw_fixed(w, 257 + i);
bw_bits(w, len - ref_lbase[i], ref_lext[i]);
bw_code(w, j, 5);
bw_bits(w, dist - ref_dbase[j], ref_dext[j]);
}
// canonical codes (RFC 1951 3.2.2) of lens[0..n-1] (lengths <= 15) into codes[0..n-1]
static void canonical(const unsigned char *lens, unsigned n, unsigned short *codes)
{
unsigned count[16], next[16];
for (unsigned l = 0; l < 16; ++l)
count[l] = 0;
for (unsigned i = 0; i < n; ++i)
count[lens[i]]++;
count[0] = 0;
unsigned c = 0;
next[0] = 0;
for (unsigned l = 1; l < 16; ++l) {
c = (c + count[l - 1]) << 1;
next[l] = c;
}
for (unsigned i = 0; i < n; ++i) {
if (lens[i] != 0) {
codes[i] = (unsigned short) next[lens[i]];
next[lens[i]]++;
} else {
codes[i] = 0;
}
}
}
// the Kraft sum of lens[0..n-1] in units of 2^-15 (a complete code: 2^15), and the number of codes
static unsigned long kraft(const unsigned char *lens, unsigned n, unsigned *used)
{
unsigned long k = 0;
unsigned u = 0;
for (unsigned i = 0; i < n; ++i) {
if (lens[i] != 0) {
k += 1ul << (15 - lens[i]);
u++;
}
}
*used = u;
return k;
}
// does inflate accept these lengths (see the header comment)? type 0: code length code, 1: literal/length, 2: distance
static int code_ok(const unsigned char *lens, unsigned n, int type)
{
unsigned used;
const unsigned long k = kraft(lens, n, &used);
if (k == 32768)
return 1;
if (type == 0)
return 0;
if (used == 1 && k == 16384)
return 1; // a single code of length 1
return type == 2 && used == 0; // no distance code at all
}
#endifharness/zlib_common.h, 155 lines
// Shared by the zlib harnesses (zlib 1.3.2 core: adler32.c, crc32.c, deflate.c, trees.c, inflate.c, inffast.c,
// inftrees.c, compress.c, uncompr.c, zutil.c).
//
// A harness draws every input from quickproof.h (nondet_*, pick), restricts it with gp_assume, and states each property
// with gp_assert (undefined behaviour when the property fails). Buffers have exactly the size the claim allows. Every
// call of inflate() or deflate() gets its input and its output space as objects of their own, allocated with exactly
// avail_in and avail_out bytes (exact_copy, exact_space): an access before next_in, after next_in + avail_in, before
// next_out or after next_out + avail_out is then outside an object, i.e. undefined behaviour in the semantics of the
// theorem, so "inflate reads only the input it is offered and writes only the space it is offered" is part of every
// law's "no undefined behaviour".
//
// The reference facts, written from the definitions, not from zlib:
// - Adler-32 (RFC 1950 8.2): s1 = 1 + the sum of the bytes, s2 = the sum of the successive values of s1, both mod
// 65521; the checksum is s2 * 65536 + s1. ref_adler32 updates a checksum byte by byte;
// - CRC-32 (RFC 1952 8, ISO 3309): the reflected polynomial 0xedb88320, register preset to all ones and inverted at
// the end. ref_crc32 updates a checksum bit by bit;
// - the zlib wrapper (RFC 1950): 2 header bytes, an optional 4-byte dictionary id (big-endian Adler-32 of the
// dictionary), the deflate data, then the big-endian Adler-32 of the uncompressed data;
// - the gzip wrapper (RFC 1952): a header of at least 10 bytes (1f 8b 08 FLG MTIME(4) XFL OS, then the optional
// fields), the deflate data, then the little-endian CRC-32 and the little-endian length mod 2^32 of the data;
// - the inflate windowBits of zlib.h: 8..15 (zlib wrapper, 2^windowBits window), 0 (zlib wrapper, the window size of
// the header), -8..-15 (raw deflate), + 16 (gzip wrapper only; 16 itself: the window size of the header), + 32
// (zlib or gzip, detected); everything else is rejected with Z_STREAM_ERROR.
#ifndef ZLIB_HARNESS_COMMON_H
#define ZLIB_HARNESS_COMMON_H
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include "quickproof.h"
#include "zlib.h"
#define GP_BASE 65521ul // the Adler-32 modulus (RFC 1950)
#define GP_POLY 0xedb88320ul // the CRC-32 polynomial, reflected (RFC 1952)
// Adler-32 of buf[0..n-1] continued from the checksum a (both halves < 65521 for a checksum).
static unsigned long ref_adler32(unsigned long a, const unsigned char *buf, unsigned long n)
{
unsigned long s1 = a & 0xffff;
unsigned long s2 = (a >> 16) & 0xffff;
for (unsigned long i = 0; i < n; ++i) {
s1 = (s1 + buf[i]) % GP_BASE;
s2 = (s2 + s1) % GP_BASE;
}
return (s2 << 16) | s1;
}
// The CRC-32 register update by one byte, without pre- or post-conditioning (the register is the 32 low bits).
static unsigned long ref_crc_byte(unsigned long c, unsigned char b)
{
c ^= b;
for (int k = 0; k < 8; ++k) {
if (c & 1)
c = (c >> 1) ^ GP_POLY;
else
c = c >> 1;
}
return c;
}
// CRC-32 of buf[0..n-1] continued from the checksum c (its 32 low bits).
static unsigned long ref_crc32(unsigned long c, const unsigned char *buf, unsigned long n)
{
c = (~c) & 0xffffffff;
for (unsigned long i = 0; i < n; ++i)
c = ref_crc_byte(c, buf[i]);
return (~c) & 0xffffffff;
}
static unsigned long be32(const unsigned char *p)
{
return ((unsigned long) p[0] << 24) | ((unsigned long) p[1] << 16) | ((unsigned long) p[2] << 8) | p[3];
}
static unsigned long le32(const unsigned char *p)
{
return ((unsigned long) p[3] << 24) | ((unsigned long) p[2] << 16) | ((unsigned long) p[1] << 8) | p[0];
}
static int bytes_same(const unsigned char *a, const unsigned char *b, unsigned long n)
{
for (unsigned long i = 0; i < n; ++i)
if (a[i] != b[i])
return 0;
return 1;
}
static void bytes_copy(unsigned char *d, const unsigned char *s, unsigned long n)
{
for (unsigned long i = 0; i < n; ++i)
d[i] = s[i];
}
// A new object of exactly n bytes holding src[0..n-1] (NULL when the allocation fails).
static unsigned char *exact_copy(const unsigned char *src, unsigned n)
{
unsigned char *p = malloc(n);
if (p != NULL)
bytes_copy(p, src, n);
return p;
}
// A new object of exactly n bytes with any contents, and a snapshot of them in *snap (NULL when an allocation fails).
static unsigned char *exact_space(unsigned n, unsigned char **snap)
{
unsigned char *p = malloc(n);
unsigned char *q = malloc(n);
if (p == NULL || q == NULL) {
free(p);
free(q);
*snap = NULL;
return NULL;
}
nondet_bytes(p, n);
bytes_copy(q, p, n);
*snap = q;
return p;
}
// inflateInit2's windowBits check (zlib.h): accepted values.
static int inflate_wbits_ok(int w)
{
if (w < 0)
return w >= -15 && w <= -8;
if (w >= 48)
return 0;
w &= 15;
return w == 0 || (w >= 8 && w <= 15);
}
// Is a value one of inflate()'s documented return codes (zlib.h)?
static int inflate_code_ok(int r)
{
return r == Z_OK || r == Z_STREAM_END || r == Z_NEED_DICT || r == Z_DATA_ERROR || r == Z_STREAM_ERROR ||
r == Z_MEM_ERROR || r == Z_BUF_ERROR;
}
// A z_stream with the default allocator (zalloc, zfree, opaque all Z_NULL: zlib uses zcalloc/zcfree, i.e. malloc and
// free) and any values in the fields the caller does not have to set.
static void stream_defaults(z_stream *s)
{
s->zalloc = Z_NULL;
s->zfree = Z_NULL;
s->opaque = Z_NULL;
s->next_in = Z_NULL;
s->avail_in = 0;
s->next_out = Z_NULL;
s->avail_out = 0;
pick(s->total_in);
pick(s->total_out);
pick(s->adler);
pick(s->data_type);
pick(s->reserved);
}
#endifThe theorem
QuickProof generated this statement from the spec, in src/contracts/x_inflate_dict.v:
Theorem x_inflate_dict : harness_safe whole_prog.src/contracts/laws.v states it on the spec's own program, whole_prog (the spec linked with the code under test), with its proof:
Theorem x_inflate_dict : harness_safe Zlib.contracts.x_inflate_dict.whole_prog.
Proof. exact (proj1 (proj2 (proj2 (proj2 (proj2 (proj2 (proj2 (proj2 (proj2 (proj2 (proj2 (proj2 (proj2 (proj2 Zlib.contracts.suite.suite_x)))))))))))))). Qed.Read as a statement about runs, it says that no run of the program has undefined behaviour or a failing check, for every value the spec can draw. That reading rests on VST's adequacy theorem, which is not yet instantiated in Rocq (formerly Coq) for QuickProof's environment.
The C files (units) its program links
adler32.ccrc32.cinflate.cinffast.cinftrees.czutil.cquickproof/libc/libc.c
What it leaves out
- What the first comment of the spec excludes, and its bounds.
- Like every spec of this proof: termination (a run that never returns is not a counterexample), and binaries built by a compiler (the theorem is about the code as CompCert defines C for x86_64, LP64), one thread.
- Where zlib reports
Z_MEM_ERROR, most specs end the run and claim nothing about it; the first comment of the spec says so. - The edits to zlib's code, listed in the repository, are tested, not proved.
The summary page says what the proof as a whole covers.
How it was proved
AI agents wrote the proof, and Rocq checks it. qp verify passes on this repository: this statement is the one generated from the spec at the contract commit, and its proof uses only Rocq's standard axioms and VST's abstract malloc library.