Coverage Report

Created: 2025-10-10 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/zlib-ng/test/fuzz/fuzzer_compress.c
Line
Count
Source
1
#include <stdio.h>
2
#include <assert.h>
3
4
#include "zbuild.h"
5
#ifdef ZLIB_COMPAT
6
#  include "zlib.h"
7
#else
8
#  include "zlib-ng.h"
9
#endif
10
11
static const uint8_t *data;
12
static size_t dataLen;
13
14
static void check_compress_level(uint8_t *compr, z_uintmax_t comprLen,
15
                                 uint8_t *uncompr, z_uintmax_t uncomprLen,
16
16.3k
                                 int level) {
17
16.3k
    PREFIX(compress2)(compr, &comprLen, data, dataLen, level);
18
16.3k
    PREFIX(uncompress)(uncompr, &uncomprLen, compr, comprLen);
19
20
    /* Make sure compress + uncompress gives back the input data. */
21
16.3k
    assert(dataLen == uncomprLen);
22
16.3k
    assert(0 == memcmp(data, uncompr, dataLen));
23
16.3k
}
24
25
8.15k
#define put_byte(s, i, c) {s[i] = (unsigned char)(c);}
26
27
4.07k
static void write_zlib_header(uint8_t *s) {
28
4.07k
    unsigned level_flags = 0; /* compression level (0..3) */
29
4.07k
    unsigned w_bits = 8; /* window size log2(w_size) (8..16) */
30
4.07k
    unsigned int header = (Z_DEFLATED + ((w_bits-8)<<4)) << 8;
31
4.07k
    header |= (level_flags << 6);
32
33
4.07k
    header += 31 - (header % 31);
34
35
    /* s is guaranteed to be longer than 2 bytes. */
36
4.07k
    put_byte(s, 0, (header >> 8));
37
4.07k
    put_byte(s, 1, (header & 0xff));
38
4.07k
}
39
40
4.07k
static void check_decompress(uint8_t *compr, z_uintmax_t comprLen) {
41
    /* We need to write a valid zlib header of size two bytes. Copy the input data
42
       in a larger buffer. Do not modify the input data to avoid libFuzzer error:
43
       fuzz target overwrites its const input. */
44
4.07k
    size_t copyLen = dataLen + 2;
45
4.07k
    uint8_t *copy = (uint8_t *)malloc(copyLen);
46
4.07k
    memcpy(copy + 2, data, dataLen);
47
4.07k
    write_zlib_header(copy);
48
49
4.07k
    PREFIX(uncompress)(compr, &comprLen, copy, (z_uintmax_t)copyLen);
50
4.07k
    free(copy);
51
4.07k
}
52
53
4.07k
int LLVMFuzzerTestOneInput(const uint8_t *d, size_t size) {
54
    /* compressBound does not provide enough space for low compression levels. */
55
4.07k
    z_size_t comprLen = 100 + 2 * PREFIX(compressBound)(size);
56
4.07k
    z_size_t uncomprLen = (z_size_t)size;
57
4.07k
    uint8_t *compr, *uncompr;
58
59
    /* Discard inputs larger than 1Mb. */
60
4.07k
    static size_t kMaxSize = 1024 * 1024;
61
62
4.07k
    if (size < 1 || size > kMaxSize)
63
0
        return 0;
64
65
4.07k
    data = d;
66
4.07k
    dataLen = size;
67
4.07k
    compr = (uint8_t *)calloc(1, comprLen);
68
4.07k
    uncompr = (uint8_t *)calloc(1, uncomprLen);
69
70
4.07k
    check_compress_level(compr, comprLen, uncompr, uncomprLen, 1);
71
4.07k
    check_compress_level(compr, comprLen, uncompr, uncomprLen, 3);
72
4.07k
    check_compress_level(compr, comprLen, uncompr, uncomprLen, 6);
73
4.07k
    check_compress_level(compr, comprLen, uncompr, uncomprLen, 7);
74
75
4.07k
    check_decompress(compr, comprLen);
76
77
4.07k
    free(compr);
78
4.07k
    free(uncompr);
79
80
    /* This function must return 0. */
81
4.07k
    return 0;
82
4.07k
}