Coverage Report

Created: 2026-07-16 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libheif/fuzzing/encoder_fuzzer.cc
Line
Count
Source
1
/*
2
 * HEIF codec.
3
 * Copyright (c) 2018 struktur AG, Joachim Bauch <bauch@struktur.de>
4
 *
5
 * This file is part of libheif.
6
 *
7
 * libheif is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Lesser General Public License as
9
 * published by the Free Software Foundation, either version 3 of
10
 * the License, or (at your option) any later version.
11
 *
12
 * libheif is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public License
18
 * along with libheif.  If not, see <http://www.gnu.org/licenses/>.
19
 */
20
21
#include <assert.h>
22
#include <string.h>
23
#include <stdlib.h>
24
25
#include <memory>
26
27
#include "libheif/heif.h"
28
29
static void generate_plane(int width, int height, uint8_t* output, int stride)
30
11.5k
{
31
  // TODO(fancycode): Fill with random data.
32
11.5k
  if (width == stride) {
33
531
    memset(output, 0, width * height);
34
531
  }
35
11.0k
  else {
36
1.18M
    for (int y = 0; y < height; y++) {
37
1.17M
      memset(output, 0, width);
38
1.17M
      output += stride;
39
1.17M
    }
40
11.0k
  }
41
11.5k
}
42
43
static size_t create_image(const uint8_t* data, size_t size, struct heif_image** image)
44
3.92k
{
45
3.92k
  if (size < 2) {
46
72
    return 0;
47
72
  }
48
49
3.85k
  int width = data[0] + 16;
50
3.85k
  int height = data[1] + 16;
51
3.85k
  data += 2;
52
3.85k
  size -= 2;
53
  // TODO(fancycode): Get colorspace/chroma from fuzzing input.
54
3.85k
  heif_colorspace colorspace = heif_colorspace_YCbCr;
55
3.85k
  heif_chroma chroma = heif_chroma_420;
56
57
3.85k
  struct heif_error err = heif_image_create(width, height, colorspace, chroma, image);
58
3.85k
  if (err.code != heif_error_Ok) {
59
0
    return 0;
60
0
  }
61
62
3.85k
  int chroma_width = (width+1)/2;
63
3.85k
  int chroma_height = (height+1)/2;
64
65
3.85k
  err = heif_image_add_plane(*image, heif_channel_Y, width, height, 8);
66
3.85k
  assert(err.code == heif_error_Ok);
67
3.85k
  err = heif_image_add_plane(*image, heif_channel_Cb, chroma_width, chroma_height, 8);
68
3.85k
  assert(err.code == heif_error_Ok);
69
3.85k
  err = heif_image_add_plane(*image, heif_channel_Cr, chroma_width, chroma_height, 8);
70
3.85k
  assert(err.code == heif_error_Ok);
71
72
3.85k
  int stride;
73
3.85k
  uint8_t* plane;
74
75
3.85k
  plane = heif_image_get_plane(*image, heif_channel_Y, &stride);
76
3.85k
  generate_plane(width, height, plane, stride);
77
78
3.85k
  plane = heif_image_get_plane(*image, heif_channel_Cb, &stride);
79
3.85k
  generate_plane(chroma_width, chroma_height, plane, stride);
80
81
3.85k
  plane = heif_image_get_plane(*image, heif_channel_Cr, &stride);
82
3.85k
  generate_plane(chroma_width, chroma_height, plane, stride);
83
84
3.85k
  return 2;
85
3.85k
}
86
87
class MemoryWriter
88
{
89
public:
90
3.85k
  MemoryWriter() : data_(nullptr), size_(0), capacity_(0)
91
3.85k
  {}
92
93
  ~MemoryWriter()
94
3.85k
  {
95
3.85k
    free(data_);
96
3.85k
  }
97
98
  const uint8_t* data() const
99
0
  { return data_; }
100
101
  size_t size() const
102
3.85k
  { return size_; }
103
104
  void write(const void* data, size_t size)
105
3.85k
  {
106
3.85k
    if (capacity_ - size_ < size) {
107
3.85k
      size_t new_capacity = capacity_ + size;
108
3.85k
      uint8_t* new_data = static_cast<uint8_t*>(malloc(new_capacity));
109
3.85k
      assert(new_data);
110
3.85k
      if (data_) {
111
0
        memcpy(new_data, data_, size_);
112
0
        free(data_);
113
0
      }
114
3.85k
      data_ = new_data;
115
3.85k
      capacity_ = new_capacity;
116
3.85k
    }
117
3.85k
    memcpy(&data_[size_], data, size);
118
3.85k
    size_ += size;
119
3.85k
  }
120
121
public:
122
  uint8_t* data_;
123
  size_t size_;
124
  size_t capacity_;
125
};
126
127
static struct heif_error writer_write(struct heif_context* ctx, const void* data, size_t size, void* userdata)
128
3.85k
{
129
3.85k
  MemoryWriter* writer = static_cast<MemoryWriter*>(userdata);
130
3.85k
  writer->write(data, size);
131
3.85k
  struct heif_error err{heif_error_Ok, heif_suberror_Unspecified, nullptr};
132
3.85k
  return err;
133
3.85k
}
134
135
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
136
3.95k
{
137
3.95k
  struct heif_error err;
138
3.95k
  std::shared_ptr<heif_context> context(heif_context_alloc(),
139
3.95k
                                        [](heif_context* c) { heif_context_free(c); });
140
3.95k
  assert(context);
141
142
3.95k
  if (size < 2) {
143
2
    return 0;
144
2
  }
145
146
3.95k
  int quality = (data[0] & 0x7F) % 101;
147
3.95k
  bool lossless = (data[0] & 0x80);
148
3.95k
  uint8_t format_uint8 = ((data[1] & 0xf0) >> 4);
149
3.95k
  uint8_t encoder_idx = data[1] & 0x0f;
150
151
3.95k
  if (format_uint8==0 || format_uint8 > 10) {
152
15
    return 0;
153
15
  }
154
3.93k
  heif_compression_format format = (heif_compression_format)format_uint8;
155
156
3.93k
  data += 2;
157
3.93k
  size -= 2;
158
159
3.93k
  static const size_t kMaxEncoders = 5;
160
3.93k
  const heif_encoder_descriptor* encoder_descriptors[kMaxEncoders];
161
3.93k
  int count = heif_get_encoder_descriptors(format,
162
3.93k
                                           nullptr,
163
3.93k
                                           encoder_descriptors, kMaxEncoders);
164
3.93k
  assert(count >= 0);
165
3.93k
  if (count == 0) {
166
1
    return 0;
167
1
  }
168
169
3.93k
  if (encoder_idx >= count) {
170
8
    return 0;
171
8
  }
172
173
3.92k
  heif_encoder* encoder;
174
3.92k
  err = heif_context_get_encoder(context.get(), encoder_descriptors[encoder_idx], &encoder);
175
3.92k
  if (err.code != heif_error_Ok) {
176
0
    return 0;
177
0
  }
178
179
3.92k
  heif_encoder_set_lossy_quality(encoder, quality);
180
3.92k
  heif_encoder_set_lossless(encoder, lossless);
181
182
3.92k
  struct heif_image* image = nullptr;
183
3.92k
  size_t read = create_image(data, size, &image);
184
3.92k
  assert(read <= size);
185
3.92k
  if (!read) {
186
72
    heif_image_release(image);
187
72
    heif_encoder_release(encoder);
188
72
    return 0;
189
72
  }
190
191
3.85k
  data += read;
192
3.85k
  size -= read;
193
194
3.85k
  struct heif_image_handle* img;
195
3.85k
  err = heif_context_encode_image(context.get(), image, encoder, nullptr, &img);
196
3.85k
  heif_image_release(image);
197
3.85k
  heif_encoder_release(encoder);
198
3.85k
  heif_image_handle_release(img);
199
3.85k
  if (err.code != heif_error_Ok) {
200
4
    return 0;
201
4
  }
202
203
3.85k
  MemoryWriter writer;
204
3.85k
  struct heif_writer w;
205
3.85k
  w.writer_api_version = 1;
206
3.85k
  w.write = writer_write;
207
3.85k
  heif_context_write(context.get(), &w, &writer);
208
3.85k
  assert(writer.size() > 0);
209
3.85k
  return 0;
210
3.85k
}