Coverage Report

Created: 2026-02-07 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fuzzer_exo.cpp
Line
Count
Source
1
// Copyright 2020 Google Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include <assert.h>
16
#include <string>
17
18
#include "include/flac_parser.h"
19
20
#include <jni.h>
21
22
// #include <android/log.h>
23
24
#include <cassert>
25
#include <cstdlib>
26
#include <cstring>
27
28
#include "common.h"
29
30
#define LOG_TAG "FLACParser"
31
32
#define LITERAL_TO_STRING_INTERNAL(x) #x
33
#define LITERAL_TO_STRING(x) LITERAL_TO_STRING_INTERNAL(x)
34
35
8.20k
#define CHECK(x) if (!(x)) return 0;
36
37
const int endian = 1;
38
4.76k
#define isBigEndian() (*(reinterpret_cast<const char *>(&endian)) == 0)
39
40
// The FLAC parser calls our C++ static callbacks using C calling conventions,
41
// inside FLAC__stream_decoder_process_until_end_of_metadata
42
// and FLAC__stream_decoder_process_single.
43
// We immediately then call our corresponding C++ instance methods
44
// with the same parameter list, but discard redundant information.
45
46
FLAC__StreamDecoderReadStatus FLACParser::read_callback(
47
    const FLAC__StreamDecoder * /* decoder */, FLAC__byte buffer[],
48
62.8k
    size_t *bytes, void *client_data) {
49
62.8k
  return reinterpret_cast<FLACParser *>(client_data)
50
62.8k
      ->readCallback(buffer, bytes);
51
62.8k
}
52
53
FLAC__StreamDecoderSeekStatus FLACParser::seek_callback(
54
    const FLAC__StreamDecoder * /* decoder */,
55
20.2k
    FLAC__uint64 absolute_byte_offset, void *client_data) {
56
20.2k
  return reinterpret_cast<FLACParser *>(client_data)
57
20.2k
      ->seekCallback(absolute_byte_offset);
58
20.2k
}
59
60
FLAC__StreamDecoderTellStatus FLACParser::tell_callback(
61
    const FLAC__StreamDecoder * /* decoder */,
62
2.13M
    FLAC__uint64 *absolute_byte_offset, void *client_data) {
63
2.13M
  return reinterpret_cast<FLACParser *>(client_data)
64
2.13M
      ->tellCallback(absolute_byte_offset);
65
2.13M
}
66
67
FLAC__StreamDecoderLengthStatus FLACParser::length_callback(
68
    const FLAC__StreamDecoder * /* decoder */, FLAC__uint64 *stream_length,
69
0
    void *client_data) {
70
0
  return reinterpret_cast<FLACParser *>(client_data)
71
0
      ->lengthCallback(stream_length);
72
0
}
73
74
FLAC__bool FLACParser::eof_callback(const FLAC__StreamDecoder * /* decoder */,
75
62.8k
                                    void *client_data) {
76
62.8k
  return reinterpret_cast<FLACParser *>(client_data)->eofCallback();
77
62.8k
}
78
79
FLAC__StreamDecoderWriteStatus FLACParser::write_callback(
80
    const FLAC__StreamDecoder * /* decoder */, const FLAC__Frame *frame,
81
8.59k
    const FLAC__int32 *const buffer[], void *client_data) {
82
8.59k
  return reinterpret_cast<FLACParser *>(client_data)
83
8.59k
      ->writeCallback(frame, buffer);
84
8.59k
}
85
86
void FLACParser::metadata_callback(const FLAC__StreamDecoder * /* decoder */,
87
                                   const FLAC__StreamMetadata *metadata,
88
12.4k
                                   void *client_data) {
89
12.4k
  reinterpret_cast<FLACParser *>(client_data)->metadataCallback(metadata);
90
12.4k
}
91
92
void FLACParser::error_callback(const FLAC__StreamDecoder * /* decoder */,
93
                                FLAC__StreamDecoderErrorStatus status,
94
2.29M
                                void *client_data) {
95
2.29M
  reinterpret_cast<FLACParser *>(client_data)->errorCallback(status);
96
2.29M
}
97
98
// These are the corresponding callbacks with C++ calling conventions
99
100
FLAC__StreamDecoderReadStatus FLACParser::readCallback(FLAC__byte buffer[],
101
62.8k
                                                       size_t *bytes) {
102
62.8k
  size_t requested = *bytes;
103
62.8k
  ssize_t actual = mDataSource->readAt(mCurrentPos, buffer, requested);
104
62.8k
  if (0 > actual) {
105
0
    *bytes = 0;
106
0
    return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
107
62.8k
  } else if (0 == actual) {
108
25.5k
    *bytes = 0;
109
25.5k
    mEOF = true;
110
25.5k
    return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
111
37.2k
  } else {
112
37.2k
    assert(actual <= requested);
113
37.2k
    *bytes = actual;
114
37.2k
    mCurrentPos += actual;
115
37.2k
    return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
116
37.2k
  }
117
62.8k
}
118
119
FLAC__StreamDecoderSeekStatus FLACParser::seekCallback(
120
20.2k
    FLAC__uint64 absolute_byte_offset) {
121
20.2k
  mCurrentPos = absolute_byte_offset;
122
20.2k
  mEOF = false;
123
20.2k
  return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
124
20.2k
}
125
126
FLAC__StreamDecoderTellStatus FLACParser::tellCallback(
127
2.13M
    FLAC__uint64 *absolute_byte_offset) {
128
2.13M
  *absolute_byte_offset = mCurrentPos;
129
2.13M
  return FLAC__STREAM_DECODER_TELL_STATUS_OK;
130
2.13M
}
131
132
FLAC__StreamDecoderLengthStatus FLACParser::lengthCallback(
133
0
    FLAC__uint64 *stream_length) {
134
0
  return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
135
0
}
136
137
62.8k
FLAC__bool FLACParser::eofCallback() { return mEOF; }
138
139
FLAC__StreamDecoderWriteStatus FLACParser::writeCallback(
140
8.59k
    const FLAC__Frame *frame, const FLAC__int32 *const buffer[]) {
141
8.59k
  if (mWriteRequested) {
142
8.50k
    mWriteRequested = false;
143
    // FLAC parser doesn't free or realloc buffer until next frame or finish
144
8.50k
    mWriteHeader = frame->header;
145
8.50k
    mWriteBuffer = buffer;
146
8.50k
    mWriteCompleted = true;
147
8.50k
    return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
148
8.50k
  } else {
149
94
    return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
150
94
  }
151
8.59k
}
152
153
12.4k
void FLACParser::metadataCallback(const FLAC__StreamMetadata *metadata) {
154
12.4k
  switch (metadata->type) {
155
5.75k
    case FLAC__METADATA_TYPE_STREAMINFO:
156
5.75k
      if (!mStreamInfoValid) {
157
4.86k
        mStreamInfo = metadata->data.stream_info;
158
4.86k
        mStreamInfoValid = true;
159
4.86k
      } else {
160
892
        break;
161
892
      }
162
4.86k
      break;
163
4.86k
    case FLAC__METADATA_TYPE_SEEKTABLE:
164
238
      mSeekTable = &metadata->data.seek_table;
165
238
      break;
166
1.93k
    case FLAC__METADATA_TYPE_VORBIS_COMMENT:
167
1.93k
      if (!mVorbisCommentsValid) {
168
141
        FLAC__StreamMetadata_VorbisComment vorbisComment =
169
141
            metadata->data.vorbis_comment;
170
116k
        for (FLAC__uint32 i = 0; i < vorbisComment.num_comments; ++i) {
171
116k
          FLAC__StreamMetadata_VorbisComment_Entry vorbisCommentEntry =
172
116k
              vorbisComment.comments[i];
173
116k
          if (vorbisCommentEntry.entry != NULL) {
174
116k
            std::string comment(
175
116k
                reinterpret_cast<char *>(vorbisCommentEntry.entry),
176
116k
                vorbisCommentEntry.length);
177
116k
            mVorbisComments.push_back(comment);
178
116k
          }
179
116k
        }
180
141
        mVorbisCommentsValid = true;
181
1.79k
      } else {
182
1.79k
        break;
183
1.79k
      }
184
141
      break;
185
4.49k
    case FLAC__METADATA_TYPE_PICTURE: {
186
4.49k
      const FLAC__StreamMetadata_Picture *parsedPicture =
187
4.49k
          &metadata->data.picture;
188
4.49k
      FlacPicture picture;
189
4.49k
      picture.mimeType.assign(std::string(parsedPicture->mime_type));
190
4.49k
      picture.description.assign(
191
4.49k
          std::string((char *)parsedPicture->description));
192
4.49k
      picture.data.assign(parsedPicture->data,
193
4.49k
                          parsedPicture->data + parsedPicture->data_length);
194
4.49k
      picture.width = parsedPicture->width;
195
4.49k
      picture.height = parsedPicture->height;
196
4.49k
      picture.depth = parsedPicture->depth;
197
4.49k
      picture.colors = parsedPicture->colors;
198
4.49k
      picture.type = parsedPicture->type;
199
4.49k
      mPictures.push_back(picture);
200
4.49k
      mPicturesValid = true;
201
4.49k
      break;
202
1.93k
    }
203
0
    default:
204
0
      break;
205
12.4k
  }
206
12.4k
}
207
208
2.29M
void FLACParser::errorCallback(FLAC__StreamDecoderErrorStatus status) {
209
2.29M
  mErrorStatus = status;
210
2.29M
}
211
212
// Copy samples from FLAC native 32-bit non-interleaved to
213
// correct bit-depth (non-zero padded), interleaved.
214
// These are candidates for optimization if needed.
215
static void copyToByteArrayBigEndian(int8_t *dst, const int *const *src,
216
                                     unsigned bytesPerSample, unsigned nSamples,
217
0
                                     unsigned nChannels) {
218
0
  for (unsigned i = 0; i < nSamples; ++i) {
219
0
    for (unsigned c = 0; c < nChannels; ++c) {
220
      // point to the first byte of the source address
221
      // and then skip the first few bytes (most significant bytes)
222
      // depending on the bit depth
223
0
      const int8_t *byteSrc =
224
0
          reinterpret_cast<const int8_t *>(&src[c][i]) + 4 - bytesPerSample;
225
0
      memcpy(dst, byteSrc, bytesPerSample);
226
0
      dst = dst + bytesPerSample;
227
0
    }
228
0
  }
229
0
}
230
231
static void copyToByteArrayLittleEndian(int8_t *dst, const int *const *src,
232
                                        unsigned bytesPerSample,
233
8.20k
                                        unsigned nSamples, unsigned nChannels) {
234
9.47M
  for (unsigned i = 0; i < nSamples; ++i) {
235
19.8M
    for (unsigned c = 0; c < nChannels; ++c) {
236
      // with little endian, the most significant bytes will be at the end
237
      // copy the bytes in little endian will remove the most significant byte
238
      // so we are good here.
239
10.3M
      memcpy(dst, &(src[c][i]), bytesPerSample);
240
10.3M
      dst = dst + bytesPerSample;
241
10.3M
    }
242
9.46M
  }
243
8.20k
}
244
245
static void copyTrespass(int8_t * /* dst */, const int *const * /* src */,
246
                         unsigned /* bytesPerSample */, unsigned /* nSamples */,
247
0
                         unsigned /* nChannels */) {
248
0
  ;
249
0
}
250
251
// FLACParser
252
253
FLACParser::FLACParser(DataSource *source)
254
6.20k
    : mDataSource(source),
255
6.20k
      mCopy(copyTrespass),
256
6.20k
      mDecoder(NULL),
257
6.20k
      mCurrentPos(0LL),
258
6.20k
      mEOF(false),
259
6.20k
      mStreamInfoValid(false),
260
6.20k
      mSeekTable(NULL),
261
6.20k
      firstFrameOffset(0LL),
262
6.20k
      mVorbisCommentsValid(false),
263
6.20k
      mPicturesValid(false),
264
6.20k
      mWriteRequested(false),
265
6.20k
      mWriteCompleted(false),
266
6.20k
      mWriteBuffer(NULL),
267
6.20k
      mErrorStatus((FLAC__StreamDecoderErrorStatus)-1) {
268
6.20k
  memset(&mStreamInfo, 0, sizeof(mStreamInfo));
269
6.20k
  memset(&mWriteHeader, 0, sizeof(mWriteHeader));
270
6.20k
}
271
272
6.20k
FLACParser::~FLACParser() {
273
6.20k
  if (mDecoder != NULL) {
274
6.20k
    FLAC__stream_decoder_delete(mDecoder);
275
6.20k
    mDecoder = NULL;
276
6.20k
  }
277
6.20k
}
278
279
6.20k
bool FLACParser::init() {
280
  // setup libFLAC parser
281
6.20k
  mDecoder = FLAC__stream_decoder_new();
282
6.20k
  if (mDecoder == NULL) {
283
    // The new should succeed, since probably all it does is a malloc
284
    // that always succeeds in Android.  But to avoid dependence on the
285
    // libFLAC internals, we check and log here.
286
0
    return false;
287
0
  }
288
6.20k
  FLAC__stream_decoder_set_md5_checking(mDecoder, false);
289
6.20k
  FLAC__stream_decoder_set_metadata_ignore_all(mDecoder);
290
6.20k
  FLAC__stream_decoder_set_metadata_respond(mDecoder,
291
6.20k
                                            FLAC__METADATA_TYPE_STREAMINFO);
292
6.20k
  FLAC__stream_decoder_set_metadata_respond(mDecoder,
293
6.20k
                                            FLAC__METADATA_TYPE_SEEKTABLE);
294
6.20k
  FLAC__stream_decoder_set_metadata_respond(mDecoder,
295
6.20k
                                            FLAC__METADATA_TYPE_VORBIS_COMMENT);
296
6.20k
  FLAC__stream_decoder_set_metadata_respond(mDecoder,
297
6.20k
                                            FLAC__METADATA_TYPE_PICTURE);
298
6.20k
  FLAC__StreamDecoderInitStatus initStatus;
299
6.20k
  initStatus = FLAC__stream_decoder_init_stream(
300
6.20k
      mDecoder, read_callback, seek_callback, tell_callback, length_callback,
301
6.20k
      eof_callback, write_callback, metadata_callback, error_callback,
302
6.20k
      reinterpret_cast<void *>(this));
303
6.20k
  if (initStatus != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
304
    // A failure here probably indicates a programming error and so is
305
    // unlikely to happen. But we check and log here similarly to above.
306
0
    return false;
307
0
  }
308
6.20k
  return true;
309
6.20k
}
310
311
6.20k
bool FLACParser::decodeMetadata() {
312
  // parse all metadata
313
6.20k
  if (!FLAC__stream_decoder_process_until_end_of_metadata(mDecoder)) {
314
1.31k
    return false;
315
1.31k
  }
316
  // store first frame offset
317
4.89k
  FLAC__stream_decoder_get_decode_position(mDecoder, &firstFrameOffset);
318
319
4.89k
  if (mStreamInfoValid) {
320
    // check channel count
321
4.83k
    if (getChannels() == 0 || getChannels() > 8) {
322
0
      return false;
323
0
    }
324
    // check bit depth
325
4.83k
    switch (getBitsPerSample()) {
326
1.12k
      case 8:
327
2.05k
      case 16:
328
2.28k
      case 24:
329
4.76k
      case 32:
330
4.76k
        break;
331
62
      default:
332
62
        return false;
333
4.83k
    }
334
    // configure the appropriate copy function based on device endianness.
335
4.76k
    if (isBigEndian()) {
336
0
      mCopy = copyToByteArrayBigEndian;
337
4.76k
    } else {
338
4.76k
      mCopy = copyToByteArrayLittleEndian;
339
4.76k
    }
340
4.76k
  } else {
341
59
    return false;
342
59
  }
343
4.76k
  return true;
344
4.89k
}
345
346
12.9k
size_t FLACParser::readBuffer(void *output, size_t output_size) {
347
12.9k
  mWriteRequested = true;
348
12.9k
  mWriteCompleted = false;
349
350
12.9k
  if (!FLAC__stream_decoder_process_single(mDecoder)) {
351
824
    return -1;
352
824
  }
353
12.1k
  if (!mWriteCompleted) {
354
3.73k
    if (FLAC__stream_decoder_get_state(mDecoder) !=
355
3.73k
        FLAC__STREAM_DECODER_END_OF_STREAM) {
356
0
    }
357
3.73k
    return -1;
358
3.73k
  }
359
360
  // verify that block header keeps the promises made by STREAMINFO
361
8.40k
  unsigned blocksize = mWriteHeader.blocksize;
362
8.40k
  if (blocksize == 0 || blocksize > getMaxBlockSize()) {
363
36
    return -1;
364
36
  }
365
8.37k
  if (mWriteHeader.sample_rate != getSampleRate() ||
366
8.25k
      mWriteHeader.channels != getChannels() ||
367
8.22k
      mWriteHeader.bits_per_sample != getBitsPerSample()) {
368
171
    return -1;
369
171
  }
370
371
8.20k
  unsigned bytesPerSample = getBitsPerSample() >> 3;
372
8.20k
  size_t bufferSize = blocksize * getChannels() * bytesPerSample;
373
8.20k
  if (bufferSize > output_size) {
374
1
    return -1;
375
1
  }
376
377
  // copy PCM from FLAC write buffer to our media buffer, with interleaving.
378
8.20k
  (*mCopy)(reinterpret_cast<int8_t *>(output), mWriteBuffer, bytesPerSample,
379
8.20k
           blocksize, getChannels());
380
381
  // fill in buffer metadata
382
8.20k
  CHECK(mWriteHeader.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
383
384
8.20k
  return bufferSize;
385
8.20k
}
386
387
bool FLACParser::getSeekPositions(int64_t timeUs,
388
0
                                  std::array<int64_t, 4> &result) {
389
0
  if (!mSeekTable) {
390
0
    return false;
391
0
  }
392
393
0
  unsigned sampleRate = getSampleRate();
394
0
  int64_t totalSamples = getTotalSamples();
395
0
  int64_t targetSampleNumber = (timeUs * sampleRate) / 1000000LL;
396
0
  if (targetSampleNumber >= totalSamples) {
397
0
    targetSampleNumber = totalSamples - 1;
398
0
  }
399
400
0
  FLAC__StreamMetadata_SeekPoint* points = mSeekTable->points;
401
0
  unsigned length = mSeekTable->num_points;
402
403
0
  for (unsigned i = length; i != 0; i--) {
404
0
    int64_t sampleNumber = points[i - 1].sample_number;
405
0
    if (sampleNumber == -1) {  // placeholder
406
0
      continue;
407
0
    }
408
0
    if (sampleNumber <= targetSampleNumber) {
409
0
      result[0] = (sampleNumber * 1000000LL) / sampleRate;
410
0
      result[1] = firstFrameOffset + points[i - 1].stream_offset;
411
0
      if (sampleNumber == targetSampleNumber || i >= length ||
412
0
          points[i].sample_number == -1) {  // placeholder
413
        // exact seek, or no following non-placeholder seek point
414
0
        result[2] = result[0];
415
0
        result[3] = result[1];
416
0
      } else {
417
0
        result[2] = (points[i].sample_number * 1000000LL) / sampleRate;
418
0
        result[3] = firstFrameOffset + points[i].stream_offset;
419
0
      }
420
0
      return true;
421
0
    }
422
0
  }
423
0
  result[0] = 0;
424
0
  result[1] = firstFrameOffset;
425
0
  result[2] = 0;
426
0
  result[3] = firstFrameOffset;
427
0
  return true;
428
0
}
429
430
namespace {
431
432
  class FuzzDataSource : public DataSource {
433
    const uint8_t *data_;
434
    size_t size_;
435
436
   public:
437
6.20k
    FuzzDataSource(const uint8_t *data, size_t size) {
438
6.20k
      data_ = data;
439
6.20k
      size_ = size;
440
6.20k
    }
441
442
62.8k
    ssize_t readAt(off64_t offset, void *const data, size_t size) {
443
62.8k
      if (offset > size_)
444
0
        return -1;
445
62.8k
      size_t remaining = size_ - offset;
446
62.8k
      if (remaining < size)
447
51.7k
        size = remaining;
448
62.8k
      memcpy(data, data_ + offset, size);
449
62.8k
      return size;
450
62.8k
    }
451
  };
452
453
}  // namespace
454
455
// Fuzz FLAC format and instrument the result as exoplayer JNI would:
456
// https://github.com/google/ExoPlayer/blob/release-v2/extensions/flac/src/main/jni/
457
6.20k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
458
6.20k
  FuzzDataSource source(data, size);
459
6.20k
  FLACParser parser(&source);
460
461
  // Early parsing
462
6.20k
  if (!parser.init() || !parser.decodeMetadata())
463
1.43k
    return 0;
464
465
4.76k
  auto streamInfo = parser.getStreamInfo();
466
467
  // Similar implementation than ExoPlayer
468
4.76k
  int buffer_size = streamInfo.max_blocksize * streamInfo.channels * 2;
469
4.76k
  assert(buffer_size >= 0);  // Not expected
470
4.76k
  auto buffer = new uint8_t[buffer_size];
471
472
12.9k
  while (parser.readBuffer(buffer, buffer_size) < ((size_t)-1));
473
4.76k
  delete[] buffer;
474
475
4.76k
  return 0;
476
4.76k
}