Coverage Report

Created: 2025-07-01 07:02

/src/compress_fuzzer.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright 2022 Google LLC
2
Licensed under the Apache License, Version 2.0 (the "License");
3
you may not use this file except in compliance with the License.
4
You may obtain a copy of the License at
5
      http://www.apache.org/licenses/LICENSE-2.0
6
Unless required by applicable law or agreed to in writing, software
7
distributed under the License is distributed on an "AS IS" BASIS,
8
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9
See the License for the specific language governing permissions and
10
limitations under the License.
11
*/
12
13
#include <stdio.h>
14
#include <stddef.h>
15
#include <stdint.h>
16
#include <string.h>
17
#include <assert.h>
18
#include <stdlib.h>
19
#include <inttypes.h>
20
#include "zlib.h"
21
22
static const uint8_t *data;
23
static size_t dataLen;
24
25
static void check_compress_level(uint8_t *compr, size_t comprLen,
26
                                 uint8_t *uncompr, size_t uncomprLen,
27
0
                                 int level) {
28
0
  compress2(compr, &comprLen, data, dataLen, level);
29
0
  uncompress(uncompr, &uncomprLen, compr, comprLen);
30
31
  /* Make sure compress + uncompress gives back the input data. */
32
0
  assert(dataLen == uncomprLen);
33
0
  assert(0 == memcmp(data, uncompr, dataLen));
34
0
}
35
36
0
#define put_byte(s, i, c) {s[i] = (unsigned char)(c);}
37
38
0
static void write_zlib_header(uint8_t *s, unsigned compression_method, unsigned flags) {
39
0
  unsigned int header = (Z_DEFLATED + ((flags)<<4)) << 8;
40
0
  header |= (compression_method << 6);
41
42
0
  header += 31 - (header % 31);
43
44
  /* s is guaranteed to be longer than 2 bytes. */
45
0
  put_byte(s, 0, (unsigned char)(header >> 8));
46
0
  put_byte(s, 1, (unsigned char)(header & 0xff));
47
0
}
48
49
0
static void check_decompress(uint8_t *compr, size_t comprLen, unsigned compression_method, unsigned flags) {
50
  /* We need to write a valid zlib header of size two bytes. Copy the input data
51
     in a larger buffer. Do not modify the input data to avoid libFuzzer error:
52
     fuzz target overwrites its const input. */
53
0
  size_t copyLen = dataLen + 2;
54
0
  uint8_t *copy = (uint8_t *)malloc(copyLen);
55
0
  memcpy(copy + 2, data, dataLen);
56
0
  write_zlib_header(copy, compression_method, flags);
57
58
0
  uncompress(compr, &comprLen, copy, copyLen);
59
0
  free(copy);
60
0
}
61
62
0
int LLVMFuzzerTestOneInput(const uint8_t *d, size_t size) {
63
0
  if (size < 10 || size > 1024 * 1024)
64
0
    return 0;
65
66
0
  const int level = d[0] % 10;
67
0
  d++,size--;
68
69
  //https://web.archive.org/web/20200220015003/http://www.onicos.com/staff/iz/formats/gzip.html
70
0
  unsigned compression_method = d[0] % 5;
71
0
  if (compression_method == 4)  //[4...7] are reserved
72
0
    compression_method = 8;
73
0
  d++,size--;
74
0
  unsigned flags = d[0] & (2 << 4);
75
0
  d++,size--;
76
77
0
  size_t comprLen = compressBound(size);
78
0
  size_t uncomprLen = size;
79
0
  uint8_t *compr = NULL, *uncompr = NULL;
80
81
0
  data = d;
82
0
  dataLen = size;
83
0
  compr = (uint8_t *)calloc(1, comprLen);
84
0
  if (!compr)
85
0
    goto err;
86
0
  uncompr = (uint8_t *)calloc(1, uncomprLen);
87
0
  if (!uncompr)
88
0
    goto err;
89
90
0
  check_compress_level(compr, comprLen, uncompr, uncomprLen, level);
91
0
  check_decompress(compr, comprLen, compression_method, flags);
92
93
0
err:
94
0
  free(compr);
95
0
  free(uncompr);
96
97
  /* This function must return 0. */
98
0
  return 0;
99
0
}