Coverage Report

Created: 2026-10-28 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/grok/tests/fuzzers/grk_decompress_mercury_fuzzer.cpp
Line
Count
Source
1
/*
2
 *    Copyright (C) 2016-2026 Grok Image Compression Inc.
3
 *
4
 *    This source code is free software: you can redistribute it and/or  modify
5
 *    it under the terms of the GNU Affero General Public License, version 3,
6
 *    as published by the Free Software Foundation.
7
 *
8
 *    This source code is distributed in the hope that it will be useful,
9
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 *    GNU Affero General Public License for more details.
12
 *
13
 *    You should have received a copy of the GNU Affero General Public License
14
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
 *
16
 */
17
18
#include <climits>
19
#include <cstddef>
20
#include <cstdint>
21
#include <cstdio>
22
#include <cstdlib>
23
#include <cstring>
24
#include <unistd.h>
25
#include "grok.h"
26
27
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv);
28
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* buf, size_t len);
29
30
static int temp_file_descriptor = -1;
31
static char temp_file_path[] = "/tmp/grk_mercury_fuzz_XXXXXX";
32
33
struct Initializer
34
{
35
  Initializer()
36
6
  {
37
6
    setenv("GRK_MERCURY", "1", 1);
38
6
    temp_file_descriptor = mkstemp(temp_file_path);
39
6
    grk_initialize(nullptr, 0, nullptr);
40
6
  }
41
};
42
int LLVMFuzzerInitialize(int* argc, char*** argv)
43
6
{
44
6
  static Initializer init;
45
6
  return 0;
46
6
}
47
int LLVMFuzzerTestOneInput(const uint8_t* buf, size_t len)
48
920
{
49
920
  grk_header_info headerInfo = {};
50
920
  grk_decompress_parameters parameters = {};
51
  // bound the decoded area so a huge declared canvas cannot OOM the fuzzer.
52
  // mercury still runs when this window covers the whole image (<=1024);
53
  // larger images fall back to the classic windowed decode.
54
920
  parameters.dw_x1 = 1024;
55
920
  parameters.dw_y1 = 1024;
56
920
  grk_object* codec = nullptr;
57
920
  grk_stream_params stream_params = {};
58
59
920
  if(temp_file_descriptor < 0)
60
0
    return 0;
61
920
  if(ftruncate(temp_file_descriptor, 0) != 0)
62
0
    return 0;
63
920
  if(lseek(temp_file_descriptor, 0, SEEK_SET) != 0)
64
0
    return 0;
65
920
  size_t written = 0;
66
1.84k
  while(written < len)
67
920
  {
68
920
    ssize_t count = write(temp_file_descriptor, buf + written, len - written);
69
920
    if(count <= 0)
70
0
      return 0;
71
920
    written += (size_t)count;
72
920
  }
73
74
920
  strncpy(stream_params.file, temp_file_path, sizeof(stream_params.file) - 1);
75
920
  codec = grk_decompress_init(&stream_params, &parameters);
76
920
  if(!codec)
77
0
    goto cleanup;
78
920
  if(!grk_decompress_read_header(codec, &headerInfo))
79
87
    goto cleanup;
80
833
  if(!grk_decompress(codec, nullptr))
81
112
    goto cleanup;
82
920
cleanup:
83
920
  grk_object_unref(codec);
84
85
920
  return 0;
86
833
}