Coverage Report

Created: 2026-05-24 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libhevc/fuzzer/hevc_dec_fuzzer.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Copyright (C) 2019 The Android Open Source Project
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at:
8
 *
9
 * http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 *****************************************************************************
18
 * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
19
 */
20
21
#include <stddef.h>
22
#include <stdint.h>
23
#include <stdio.h>
24
#include <stdlib.h>
25
#include <string.h>
26
27
#include <algorithm>
28
#include <memory>
29
30
#include "ihevc_typedefs.h"
31
#include "ihevcd_cxa.h"
32
#include "iv.h"
33
#include "ivd.h"
34
35
#include "fuzzer/FuzzedDataProvider.h"
36
37
#define NELEMENTS(x) (sizeof(x) / sizeof(x[0]))
38
346k
#define ivd_api_function ihevcd_cxa_api_function
39
const IV_COLOR_FORMAT_T supportedColorFormats[] = {
40
    IV_YUV_420P,   IV_YUV_420SP_UV, IV_YUV_420SP_VU,
41
    IV_GRAY};
42
43
/* Decoder ignores invalid arch, i.e. for arm build, if SSSE3 is requested,
44
 * decoder defaults to a supported configuration. So same set of supported
45
 * architectures can be used in arm/arm64/x86 builds */
46
const IVD_ARCH_T supportedArchitectures[] = {
47
    ARCH_ARM_NONEON,  ARCH_ARM_A9Q,   ARCH_ARM_NEONINTR, ARCH_ARMV8_GENERIC,
48
    ARCH_X86_GENERIC, ARCH_X86_SSSE3, ARCH_X86_SSE42};
49
50
const static int kMaxNumDecodeCalls = 100;
51
const static int kSupportedColorFormats = NELEMENTS(supportedColorFormats);
52
const static int kSupportedArchitectures = NELEMENTS(supportedArchitectures);
53
const static int kMaxCores = 4;
54
341k
void *iv_aligned_malloc(void *ctxt, WORD32 alignment, WORD32 size) {
55
341k
  void *buf = NULL;
56
341k
  (void)ctxt;
57
341k
  if (0 != posix_memalign(&buf, alignment, size)) {
58
0
      return NULL;
59
0
  }
60
341k
  return buf;
61
341k
}
62
63
319k
void iv_aligned_free(void *ctxt, void *buf) {
64
319k
  (void)ctxt;
65
319k
  free(buf);
66
319k
}
67
68
class Codec {
69
 public:
70
  Codec(FuzzedDataProvider &fdp);
71
  ~Codec();
72
73
  void createCodec(FuzzedDataProvider &fdp);
74
  void deleteCodec();
75
  void resetCodec();
76
  void setCores(FuzzedDataProvider &fdp);
77
  void allocFrame();
78
  void freeFrame();
79
  void decodeHeader(const uint8_t *data, size_t size);
80
  IV_API_CALL_STATUS_T decodeFrame(const uint8_t *data, size_t size,
81
                                   size_t *bytesConsumed);
82
  void setParams(IVD_VIDEO_DECODE_MODE_T mode);
83
  void setArchitecture(FuzzedDataProvider &fdp);
84
85
 private:
86
  IV_COLOR_FORMAT_T mColorFormat;
87
  iv_obj_t *mCodec;
88
  ivd_out_bufdesc_t mOutBufHandle;
89
  uint32_t mWidth;
90
  uint32_t mHeight;
91
};
92
93
9.25k
Codec::Codec(FuzzedDataProvider &fdp) {
94
9.25k
  mColorFormat =
95
9.25k
      (IV_COLOR_FORMAT_T)fdp.PickValueInArray(supportedColorFormats);
96
9.25k
  mCodec = nullptr;
97
9.25k
  mWidth = 0;
98
9.25k
  mHeight = 0;
99
100
9.25k
  memset(&mOutBufHandle, 0, sizeof(mOutBufHandle));
101
9.25k
}
102
103
9.46k
Codec::~Codec() {}
104
105
9.25k
void Codec::createCodec(FuzzedDataProvider &fdp) {
106
9.25k
  IV_API_CALL_STATUS_T ret;
107
9.25k
  ihevcd_cxa_create_ip_t create_ip{};
108
9.25k
  ihevcd_cxa_create_op_t create_op{};
109
9.25k
  void *fxns = (void *)&ivd_api_function;
110
111
9.25k
  create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
112
9.25k
  create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0;
113
9.25k
  create_ip.s_ivd_create_ip_t.e_output_format = mColorFormat;
114
9.25k
  create_ip.u4_keep_threads_active = 1;
115
9.25k
  create_ip.s_ivd_create_ip_t.pf_aligned_alloc = iv_aligned_malloc;
116
9.25k
  create_ip.s_ivd_create_ip_t.pf_aligned_free = iv_aligned_free;
117
9.25k
  create_ip.s_ivd_create_ip_t.pv_mem_ctxt = NULL;
118
9.25k
  create_ip.u4_enable_yuv_formats = 0b1111; // Enable 400, 420, 422 and 444
119
9.25k
  create_ip.s_ivd_create_ip_t.u4_size = sizeof(ihevcd_cxa_create_ip_t);
120
9.25k
  create_op.s_ivd_create_op_t.u4_size = sizeof(ihevcd_cxa_create_op_t);
121
122
9.25k
  ret = ivd_api_function(NULL, (void *)&create_ip, (void *)&create_op);
123
9.25k
  if (ret != IV_SUCCESS) {
124
0
    return;
125
0
  }
126
9.25k
  mCodec = (iv_obj_t *)create_op.s_ivd_create_op_t.pv_handle;
127
9.25k
  mCodec->pv_fxns = fxns;
128
9.25k
  mCodec->u4_size = sizeof(iv_obj_t);
129
9.25k
}
130
131
9.25k
void Codec::deleteCodec() {
132
9.25k
  ivd_delete_ip_t delete_ip{};
133
9.25k
  ivd_delete_op_t delete_op{};
134
135
9.25k
  delete_ip.e_cmd = IVD_CMD_DELETE;
136
9.25k
  delete_ip.u4_size = sizeof(ivd_delete_ip_t);
137
9.25k
  delete_op.u4_size = sizeof(ivd_delete_op_t);
138
139
9.25k
  ivd_api_function(mCodec, (void *)&delete_ip, (void *)&delete_op);
140
9.25k
}
141
142
2.51k
void Codec::resetCodec() {
143
2.51k
  ivd_ctl_reset_ip_t s_ctl_ip{};
144
2.51k
  ivd_ctl_reset_op_t s_ctl_op{};
145
146
2.51k
  s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
147
2.51k
  s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
148
2.51k
  s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
149
2.51k
  s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t);
150
151
2.51k
  ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
152
2.51k
}
153
154
9.25k
void Codec::setCores(FuzzedDataProvider &fdp) {
155
9.25k
  ihevcd_cxa_ctl_set_num_cores_ip_t s_ctl_ip{};
156
9.25k
  ihevcd_cxa_ctl_set_num_cores_op_t s_ctl_op{};
157
9.25k
  s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
158
9.25k
  s_ctl_ip.e_sub_cmd =
159
9.25k
      (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_SET_NUM_CORES;
160
9.25k
  s_ctl_ip.u4_num_cores = (fdp.ConsumeIntegral<uint8_t>() % kMaxCores) + 1;
161
9.25k
  s_ctl_ip.u4_size = sizeof(ihevcd_cxa_ctl_set_num_cores_ip_t);
162
9.25k
  s_ctl_op.u4_size = sizeof(ihevcd_cxa_ctl_set_num_cores_op_t);
163
164
9.25k
  ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
165
9.25k
}
166
167
18.5k
void Codec::setParams(IVD_VIDEO_DECODE_MODE_T mode) {
168
18.5k
  ivd_ctl_set_config_ip_t s_ctl_ip{};
169
18.5k
  ivd_ctl_set_config_op_t s_ctl_op{};
170
171
18.5k
  s_ctl_ip.u4_disp_wd = 0;
172
18.5k
  s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;
173
18.5k
  s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
174
18.5k
  s_ctl_ip.e_vid_dec_mode = mode;
175
18.5k
  s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
176
18.5k
  s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
177
18.5k
  s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
178
18.5k
  s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
179
180
18.5k
  ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
181
18.5k
}
182
183
9.25k
void Codec::setArchitecture(FuzzedDataProvider &fdp) {
184
9.25k
  ihevcd_cxa_ctl_set_processor_ip_t s_ctl_ip{};
185
9.25k
  ihevcd_cxa_ctl_set_processor_op_t s_ctl_op{};
186
9.25k
  s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
187
9.25k
  s_ctl_ip.e_sub_cmd =
188
9.25k
      (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_SET_PROCESSOR;
189
9.25k
  s_ctl_ip.u4_arch = (IVD_ARCH_T)fdp.PickValueInArray(supportedArchitectures);
190
9.25k
  s_ctl_ip.u4_soc = SOC_GENERIC;
191
9.25k
  s_ctl_ip.u4_size = sizeof(ihevcd_cxa_ctl_set_processor_ip_t);
192
9.25k
  s_ctl_op.u4_size = sizeof(ihevcd_cxa_ctl_set_processor_op_t);
193
194
9.25k
  ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
195
9.25k
}
196
19.9k
void Codec::freeFrame() {
197
42.4k
  for (int i = 0; i < mOutBufHandle.u4_num_bufs; i++) {
198
22.5k
    if (mOutBufHandle.pu1_bufs[i]) {
199
22.5k
      free(mOutBufHandle.pu1_bufs[i]);
200
22.5k
      mOutBufHandle.pu1_bufs[i] = nullptr;
201
22.5k
    }
202
22.5k
  }
203
19.9k
}
204
205
10.6k
void Codec::allocFrame() {
206
10.6k
  size_t sizes[4] = {0};
207
10.6k
  size_t num_bufs = 0;
208
209
10.6k
  freeFrame();
210
211
10.6k
  memset(&mOutBufHandle, 0, sizeof(mOutBufHandle));
212
213
10.6k
  switch (mColorFormat) {
214
3.43k
    case IV_YUV_420SP_UV:
215
3.43k
      [[fallthrough]];
216
5.26k
    case IV_YUV_420SP_VU:
217
5.26k
      sizes[0] = mWidth * mHeight;
218
5.26k
      sizes[1] = mWidth * mHeight >> 1;
219
5.26k
      num_bufs = 2;
220
5.26k
      break;
221
2.09k
    case IV_GRAY:
222
2.09k
      sizes[0] = mWidth * mHeight;
223
2.09k
      num_bufs = 1;
224
2.09k
      break;
225
3.30k
    case IV_YUV_420P:
226
3.30k
      [[fallthrough]];
227
3.30k
    default:
228
3.30k
      sizes[0] = mWidth * mHeight;
229
3.30k
      sizes[1] = mWidth * mHeight >> 2;
230
3.30k
      sizes[2] = mWidth * mHeight >> 2;
231
3.30k
      num_bufs = 3;
232
3.30k
      break;
233
10.6k
  }
234
10.6k
  mOutBufHandle.u4_num_bufs = num_bufs;
235
33.1k
  for (int i = 0; i < num_bufs; i++) {
236
22.5k
    mOutBufHandle.u4_min_out_buf_size[i] = sizes[i];
237
22.5k
    mOutBufHandle.pu1_bufs[i] = (UWORD8 *)iv_aligned_malloc(NULL, 16, sizes[i]);
238
22.5k
  }
239
10.6k
}
240
241
9.25k
void Codec::decodeHeader(const uint8_t *data, size_t size) {
242
9.25k
  setParams(IVD_DECODE_HEADER);
243
244
9.25k
  size_t numDecodeCalls = 0;
245
246
150k
  while (size > 0 && numDecodeCalls < kMaxNumDecodeCalls) {
247
147k
    IV_API_CALL_STATUS_T ret;
248
147k
    ivd_video_decode_ip_t dec_ip{};
249
147k
    ivd_video_decode_op_t dec_op{};
250
147k
    size_t bytes_consumed;
251
252
147k
    memset(&dec_ip, 0, sizeof(dec_ip));
253
147k
    memset(&dec_op, 0, sizeof(dec_op));
254
255
147k
    dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
256
147k
    dec_ip.u4_ts = 0;
257
147k
    dec_ip.pv_stream_buffer = (void *)data;
258
147k
    dec_ip.u4_num_Bytes = size;
259
147k
    dec_ip.u4_size = sizeof(ivd_video_decode_ip_t);
260
147k
    dec_op.u4_size = sizeof(ivd_video_decode_op_t);
261
262
147k
    ret = ivd_api_function(mCodec, (void *)&dec_ip, (void *)&dec_op);
263
264
147k
    bytes_consumed = dec_op.u4_num_bytes_consumed;
265
    /* If no bytes are consumed, then consume 4 bytes to ensure fuzzer proceeds
266
     * to feed next data */
267
147k
    if (!bytes_consumed) bytes_consumed = 4;
268
269
147k
    bytes_consumed = std::min(size, bytes_consumed);
270
271
147k
    data += bytes_consumed;
272
147k
    size -= bytes_consumed;
273
147k
    numDecodeCalls++;
274
275
147k
    mWidth = std::min(dec_op.u4_pic_wd, (UWORD32)10240);
276
147k
    mHeight = std::min(dec_op.u4_pic_ht, (UWORD32)10240);
277
278
    /* Break after successful header decode */
279
147k
    if (mWidth && mHeight) {
280
5.56k
      break;
281
5.56k
    }
282
147k
  }
283
  /* if width / height are invalid, set them to defaults */
284
9.25k
  if (!mWidth) mWidth = 1920;
285
9.25k
  if (!mHeight) mHeight = 1088;
286
9.25k
}
287
288
IV_API_CALL_STATUS_T Codec::decodeFrame(const uint8_t *data, size_t size,
289
129k
                                        size_t *bytesConsumed) {
290
129k
  IV_API_CALL_STATUS_T ret;
291
129k
  ivd_video_decode_ip_t dec_ip{};
292
129k
  ivd_video_decode_op_t dec_op{};
293
294
129k
  memset(&dec_ip, 0, sizeof(dec_ip));
295
129k
  memset(&dec_op, 0, sizeof(dec_op));
296
297
129k
  dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
298
129k
  dec_ip.u4_ts = 0;
299
129k
  dec_ip.pv_stream_buffer = (void *)data;
300
129k
  dec_ip.u4_num_Bytes = size;
301
129k
  dec_ip.u4_size = sizeof(ivd_video_decode_ip_t);
302
129k
  dec_ip.s_out_buffer = mOutBufHandle;
303
304
129k
  dec_op.u4_size = sizeof(ivd_video_decode_op_t);
305
306
129k
  ret = ivd_api_function(mCodec, (void *)&dec_ip, (void *)&dec_op);
307
308
  /* In case of change in resolution, reset codec and feed the same data again
309
   */
310
129k
  if (IVD_RES_CHANGED == (dec_op.u4_error_code & 0xFF)) {
311
2.51k
    resetCodec();
312
2.51k
    ret = ivd_api_function(mCodec, (void *)&dec_ip, (void *)&dec_op);
313
2.51k
  }
314
129k
  *bytesConsumed = dec_op.u4_num_bytes_consumed;
315
316
  /* If no bytes are consumed, then consume 4 bytes to ensure fuzzer proceeds
317
   * to feed next data */
318
129k
  if (!*bytesConsumed) *bytesConsumed = 4;
319
320
129k
  if (dec_op.u4_pic_wd && dec_op.u4_pic_ht &&
321
86.0k
      (mWidth != dec_op.u4_pic_wd || mHeight != dec_op.u4_pic_ht)) {
322
1.40k
    mWidth = std::min(dec_op.u4_pic_wd, (UWORD32)10240);
323
1.40k
    mHeight = std::min(dec_op.u4_pic_ht, (UWORD32)10240);
324
1.40k
    allocFrame();
325
1.40k
  }
326
327
129k
  return ret;
328
129k
}
329
330
9.25k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
331
9.25k
  if (size < 1) {
332
0
    return 0;
333
0
  }
334
9.25k
  FuzzedDataProvider fdp(data, size);
335
336
9.25k
  size_t numDecodeCalls = 0;
337
9.25k
  Codec *codec = new Codec(fdp);
338
9.25k
  codec->createCodec(fdp);
339
9.25k
  codec->setArchitecture(fdp);
340
9.25k
  codec->setCores(fdp);
341
9.25k
  codec->decodeHeader(data, size);
342
9.25k
  codec->setParams(IVD_DECODE_FRAME);
343
9.25k
  codec->allocFrame();
344
345
138k
  while (size > 0 && numDecodeCalls < kMaxNumDecodeCalls) {
346
129k
    IV_API_CALL_STATUS_T ret;
347
129k
    size_t bytesConsumed;
348
129k
    ret = codec->decodeFrame(data, size, &bytesConsumed);
349
350
129k
    bytesConsumed = std::min(size, bytesConsumed);
351
129k
    data += bytesConsumed;
352
129k
    size -= bytesConsumed;
353
129k
    numDecodeCalls++;
354
129k
  }
355
356
9.25k
  codec->freeFrame();
357
9.25k
  codec->deleteCodec();
358
9.25k
  delete codec;
359
9.25k
  return 0;
360
9.25k
}