Coverage Report

Created: 2025-09-04 06:50

/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_size_t comprLen,
15
                                 uint8_t *uncompr, z_size_t uncomprLen,
16
17.3k
                                 int level) {
17
17.3k
    PREFIX(compress2)(compr, &comprLen, data, dataLen, level);
18
17.3k
    PREFIX(uncompress)(uncompr, &uncomprLen, compr, comprLen);
19
20
    /* Make sure compress + uncompress gives back the input data. */
21
17.3k
    assert(dataLen == uncomprLen);
22
17.3k
    assert(0 == memcmp(data, uncompr, dataLen));
23
17.3k
}
24
25
8.65k
#define put_byte(s, i, c) {s[i] = (unsigned char)(c);}
26
27
4.32k
static void write_zlib_header(uint8_t *s) {
28
4.32k
    unsigned level_flags = 0; /* compression level (0..3) */
29
4.32k
    unsigned w_bits = 8; /* window size log2(w_size) (8..16) */
30
4.32k
    unsigned int header = (Z_DEFLATED + ((w_bits-8)<<4)) << 8;
31
4.32k
    header |= (level_flags << 6);
32
33
4.32k
    header += 31 - (header % 31);
34
35
    /* s is guaranteed to be longer than 2 bytes. */
36
4.32k
    put_byte(s, 0, (header >> 8));
37
4.32k
    put_byte(s, 1, (header & 0xff));
38
4.32k
}
39
40
4.32k
static void check_decompress(uint8_t *compr, size_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.32k
    size_t copyLen = dataLen + 2;
45
4.32k
    uint8_t *copy = (uint8_t *)malloc(copyLen);
46
4.32k
    memcpy(copy + 2, data, dataLen);
47
4.32k
    write_zlib_header(copy);
48
49
4.32k
    PREFIX(uncompress)(compr, &comprLen, copy, copyLen);
50
4.32k
    free(copy);
51
4.32k
}
52
53
8.40k
int LLVMFuzzerTestOneInput(const uint8_t *d, size_t size) {
54
    /* compressBound does not provide enough space for low compression levels. */
55
8.40k
    z_size_t comprLen = 100 + 2 * PREFIX(compressBound)(size);
56
8.40k
    z_size_t uncomprLen = (z_size_t)size;
57
8.40k
    uint8_t *compr, *uncompr;
58
59
    /* Discard inputs larger than 1Mb. */
60
8.40k
    static size_t kMaxSize = 1024 * 1024;
61
62
8.40k
    if (size < 1 || size > kMaxSize)
63
4
        return 0;
64
65
8.39k
    data = d;
66
8.39k
    dataLen = size;
67
8.39k
    compr = (uint8_t *)calloc(1, comprLen);
68
8.39k
    uncompr = (uint8_t *)calloc(1, uncomprLen);
69
70
8.39k
    check_compress_level(compr, comprLen, uncompr, uncomprLen, 1);
71
8.39k
    check_compress_level(compr, comprLen, uncompr, uncomprLen, 3);
72
8.39k
    check_compress_level(compr, comprLen, uncompr, uncomprLen, 6);
73
8.39k
    check_compress_level(compr, comprLen, uncompr, uncomprLen, 7);
74
75
8.39k
    check_decompress(compr, comprLen);
76
77
8.39k
    free(compr);
78
8.39k
    free(uncompr);
79
80
    /* This function must return 0. */
81
8.39k
    return 0;
82
8.40k
}