Coverage Report

Created: 2025-11-11 06:36

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
0
{
31
  // TODO(fancycode): Fill with random data.
32
0
  if (width == stride) {
33
0
    memset(output, 0, width * height);
34
0
  }
35
0
  else {
36
0
    for (int y = 0; y < height; y++) {
37
0
      memset(output, 0, width);
38
0
      output += stride;
39
0
    }
40
0
  }
41
0
}
42
43
static size_t create_image(const uint8_t* data, size_t size, struct heif_image** image)
44
0
{
45
0
  if (size < 2) {
46
0
    return 0;
47
0
  }
48
49
0
  int width = data[0] + 16;
50
0
  int height = data[1] + 16;
51
0
  data += 2;
52
0
  size -= 2;
53
  // TODO(fancycode): Get colorspace/chroma from fuzzing input.
54
0
  heif_colorspace colorspace = heif_colorspace_YCbCr;
55
0
  heif_chroma chroma = heif_chroma_420;
56
57
0
  struct heif_error err = heif_image_create(width, height, colorspace, chroma, image);
58
0
  if (err.code != heif_error_Ok) {
59
0
    return 0;
60
0
  }
61
62
0
  int chroma_width = (width+1)/2;
63
0
  int chroma_height = (height+1)/2;
64
65
0
  err = heif_image_add_plane(*image, heif_channel_Y, width, height, 8);
66
0
  assert(err.code == heif_error_Ok);
67
0
  err = heif_image_add_plane(*image, heif_channel_Cb, chroma_width, chroma_height, 8);
68
0
  assert(err.code == heif_error_Ok);
69
0
  err = heif_image_add_plane(*image, heif_channel_Cr, chroma_width, chroma_height, 8);
70
0
  assert(err.code == heif_error_Ok);
71
72
0
  int stride;
73
0
  uint8_t* plane;
74
75
0
  plane = heif_image_get_plane(*image, heif_channel_Y, &stride);
76
0
  generate_plane(width, height, plane, stride);
77
78
0
  plane = heif_image_get_plane(*image, heif_channel_Cb, &stride);
79
0
  generate_plane(chroma_width, chroma_height, plane, stride);
80
81
0
  plane = heif_image_get_plane(*image, heif_channel_Cr, &stride);
82
0
  generate_plane(chroma_width, chroma_height, plane, stride);
83
84
0
  return 2;
85
0
}
86
87
class MemoryWriter
88
{
89
public:
90
0
  MemoryWriter() : data_(nullptr), size_(0), capacity_(0)
91
0
  {}
92
93
  ~MemoryWriter()
94
0
  {
95
0
    free(data_);
96
0
  }
97
98
  const uint8_t* data() const
99
0
  { return data_; }
100
101
  size_t size() const
102
0
  { return size_; }
103
104
  void write(const void* data, size_t size)
105
0
  {
106
0
    if (capacity_ - size_ < size) {
107
0
      size_t new_capacity = capacity_ + size;
108
0
      uint8_t* new_data = static_cast<uint8_t*>(malloc(new_capacity));
109
0
      assert(new_data);
110
0
      if (data_) {
111
0
        memcpy(new_data, data_, size_);
112
0
        free(data_);
113
0
      }
114
0
      data_ = new_data;
115
0
      capacity_ = new_capacity;
116
0
    }
117
0
    memcpy(&data_[size_], data, size);
118
0
    size_ += size;
119
0
  }
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
0
{
129
0
  MemoryWriter* writer = static_cast<MemoryWriter*>(userdata);
130
0
  writer->write(data, size);
131
0
  struct heif_error err{heif_error_Ok, heif_suberror_Unspecified, nullptr};
132
0
  return err;
133
0
}
134
135
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
136
25
{
137
25
  struct heif_error err;
138
25
  std::shared_ptr<heif_context> context(heif_context_alloc(),
139
25
                                        [](heif_context* c) { heif_context_free(c); });
140
25
  assert(context);
141
142
25
  if (size < 2) {
143
2
    return 0;
144
2
  }
145
146
23
  int quality = (data[0] & 0x7F) % 101;
147
23
  bool lossless = (data[1] & 0x80);
148
23
  bool use_avif = (data[1] & 0x40);
149
23
  data += 2;
150
23
  size -= 2;
151
152
23
  static const size_t kMaxEncoders = 5;
153
23
  const heif_encoder_descriptor* encoder_descriptors[kMaxEncoders];
154
23
  int count = heif_get_encoder_descriptors(use_avif ? heif_compression_AV1 : heif_compression_HEVC,
155
23
                                           nullptr,
156
23
                                           encoder_descriptors, kMaxEncoders);
157
23
  assert(count >= 0);
158
23
  if (count == 0) {
159
23
    return 0;
160
23
  }
161
162
0
  heif_encoder* encoder;
163
0
  err = heif_context_get_encoder(context.get(), encoder_descriptors[0], &encoder);
164
0
  if (err.code != heif_error_Ok) {
165
0
    return 0;
166
0
  }
167
168
0
  heif_encoder_set_lossy_quality(encoder, quality);
169
0
  heif_encoder_set_lossless(encoder, lossless);
170
171
0
  struct heif_image* image = nullptr;
172
0
  size_t read = create_image(data, size, &image);
173
0
  assert(read <= size);
174
0
  if (!read) {
175
0
    heif_image_release(image);
176
0
    heif_encoder_release(encoder);
177
0
    return 0;
178
0
  }
179
180
0
  data += read;
181
0
  size -= read;
182
183
0
  struct heif_image_handle* img;
184
0
  err = heif_context_encode_image(context.get(), image, encoder, nullptr, &img);
185
0
  heif_image_release(image);
186
0
  heif_encoder_release(encoder);
187
0
  heif_image_handle_release(img);
188
0
  if (err.code != heif_error_Ok) {
189
0
    return 0;
190
0
  }
191
192
0
  MemoryWriter writer;
193
0
  struct heif_writer w;
194
0
  w.writer_api_version = 1;
195
0
  w.write = writer_write;
196
0
  heif_context_write(context.get(), &w, &writer);
197
0
  assert(writer.size() > 0);
198
0
  return 0;
199
0
}