Coverage Report

Created: 2025-08-03 06:34

/src/fuzzer_exo.cpp
Line
Count
Source (jump to first uncovered line)
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
11.9k
#define CHECK(x) if (!(x)) return 0;
36
37
const int endian = 1;
38
4.83k
#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
109k
    size_t *bytes, void *client_data) {
49
109k
  return reinterpret_cast<FLACParser *>(client_data)
50
109k
      ->readCallback(buffer, bytes);
51
109k
}
52
53
FLAC__StreamDecoderSeekStatus FLACParser::seek_callback(
54
    const FLAC__StreamDecoder * /* decoder */,
55
30.8k
    FLAC__uint64 absolute_byte_offset, void *client_data) {
56
30.8k
  return reinterpret_cast<FLACParser *>(client_data)
57
30.8k
      ->seekCallback(absolute_byte_offset);
58
30.8k
}
59
60
FLAC__StreamDecoderTellStatus FLACParser::tell_callback(
61
    const FLAC__StreamDecoder * /* decoder */,
62
1.95M
    FLAC__uint64 *absolute_byte_offset, void *client_data) {
63
1.95M
  return reinterpret_cast<FLACParser *>(client_data)
64
1.95M
      ->tellCallback(absolute_byte_offset);
65
1.95M
}
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
109k
                                    void *client_data) {
76
109k
  return reinterpret_cast<FLACParser *>(client_data)->eofCallback();
77
109k
}
78
79
FLAC__StreamDecoderWriteStatus FLACParser::write_callback(
80
    const FLAC__StreamDecoder * /* decoder */, const FLAC__Frame *frame,
81
12.4k
    const FLAC__int32 *const buffer[], void *client_data) {
82
12.4k
  return reinterpret_cast<FLACParser *>(client_data)
83
12.4k
      ->writeCallback(frame, buffer);
84
12.4k
}
85
86
void FLACParser::metadata_callback(const FLAC__StreamDecoder * /* decoder */,
87
                                   const FLAC__StreamMetadata *metadata,
88
14.7k
                                   void *client_data) {
89
14.7k
  reinterpret_cast<FLACParser *>(client_data)->metadataCallback(metadata);
90
14.7k
}
91
92
void FLACParser::error_callback(const FLAC__StreamDecoder * /* decoder */,
93
                                FLAC__StreamDecoderErrorStatus status,
94
2.30M
                                void *client_data) {
95
2.30M
  reinterpret_cast<FLACParser *>(client_data)->errorCallback(status);
96
2.30M
}
97
98
// These are the corresponding callbacks with C++ calling conventions
99
100
FLAC__StreamDecoderReadStatus FLACParser::readCallback(FLAC__byte buffer[],
101
109k
                                                       size_t *bytes) {
102
109k
  size_t requested = *bytes;
103
109k
  ssize_t actual = mDataSource->readAt(mCurrentPos, buffer, requested);
104
109k
  if (0 > actual) {
105
0
    *bytes = 0;
106
0
    return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
107
109k
  } else if (0 == actual) {
108
34.7k
    *bytes = 0;
109
34.7k
    mEOF = true;
110
34.7k
    return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
111
74.3k
  } else {
112
74.3k
    assert(actual <= requested);
113
74.3k
    *bytes = actual;
114
74.3k
    mCurrentPos += actual;
115
74.3k
    return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
116
74.3k
  }
117
109k
}
118
119
FLAC__StreamDecoderSeekStatus FLACParser::seekCallback(
120
30.8k
    FLAC__uint64 absolute_byte_offset) {
121
30.8k
  mCurrentPos = absolute_byte_offset;
122
30.8k
  mEOF = false;
123
30.8k
  return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
124
30.8k
}
125
126
FLAC__StreamDecoderTellStatus FLACParser::tellCallback(
127
1.95M
    FLAC__uint64 *absolute_byte_offset) {
128
1.95M
  *absolute_byte_offset = mCurrentPos;
129
1.95M
  return FLAC__STREAM_DECODER_TELL_STATUS_OK;
130
1.95M
}
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
109k
FLAC__bool FLACParser::eofCallback() { return mEOF; }
138
139
FLAC__StreamDecoderWriteStatus FLACParser::writeCallback(
140
12.4k
    const FLAC__Frame *frame, const FLAC__int32 *const buffer[]) {
141
12.4k
  if (mWriteRequested) {
142
12.3k
    mWriteRequested = false;
143
    // FLAC parser doesn't free or realloc buffer until next frame or finish
144
12.3k
    mWriteHeader = frame->header;
145
12.3k
    mWriteBuffer = buffer;
146
12.3k
    mWriteCompleted = true;
147
12.3k
    return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
148
12.3k
  } else {
149
110
    return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
150
110
  }
151
12.4k
}
152
153
14.7k
void FLACParser::metadataCallback(const FLAC__StreamMetadata *metadata) {
154
14.7k
  switch (metadata->type) {
155
6.08k
    case FLAC__METADATA_TYPE_STREAMINFO:
156
6.08k
      if (!mStreamInfoValid) {
157
4.93k
        mStreamInfo = metadata->data.stream_info;
158
4.93k
        mStreamInfoValid = true;
159
4.93k
      } else {
160
1.15k
        break;
161
1.15k
      }
162
4.93k
      break;
163
4.93k
    case FLAC__METADATA_TYPE_SEEKTABLE:
164
125
      mSeekTable = &metadata->data.seek_table;
165
125
      break;
166
1.36k
    case FLAC__METADATA_TYPE_VORBIS_COMMENT:
167
1.36k
      if (!mVorbisCommentsValid) {
168
152
        FLAC__StreamMetadata_VorbisComment vorbisComment =
169
152
            metadata->data.vorbis_comment;
170
90.3k
        for (FLAC__uint32 i = 0; i < vorbisComment.num_comments; ++i) {
171
90.1k
          FLAC__StreamMetadata_VorbisComment_Entry vorbisCommentEntry =
172
90.1k
              vorbisComment.comments[i];
173
90.1k
          if (vorbisCommentEntry.entry != NULL) {
174
90.1k
            std::string comment(
175
90.1k
                reinterpret_cast<char *>(vorbisCommentEntry.entry),
176
90.1k
                vorbisCommentEntry.length);
177
90.1k
            mVorbisComments.push_back(comment);
178
90.1k
          }
179
90.1k
        }
180
152
        mVorbisCommentsValid = true;
181
1.21k
      } else {
182
1.21k
        break;
183
1.21k
      }
184
152
      break;
185
7.18k
    case FLAC__METADATA_TYPE_PICTURE: {
186
7.18k
      const FLAC__StreamMetadata_Picture *parsedPicture =
187
7.18k
          &metadata->data.picture;
188
7.18k
      FlacPicture picture;
189
7.18k
      picture.mimeType.assign(std::string(parsedPicture->mime_type));
190
7.18k
      picture.description.assign(
191
7.18k
          std::string((char *)parsedPicture->description));
192
7.18k
      picture.data.assign(parsedPicture->data,
193
7.18k
                          parsedPicture->data + parsedPicture->data_length);
194
7.18k
      picture.width = parsedPicture->width;
195
7.18k
      picture.height = parsedPicture->height;
196
7.18k
      picture.depth = parsedPicture->depth;
197
7.18k
      picture.colors = parsedPicture->colors;
198
7.18k
      picture.type = parsedPicture->type;
199
7.18k
      mPictures.push_back(picture);
200
7.18k
      mPicturesValid = true;
201
7.18k
      break;
202
1.36k
    }
203
0
    default:
204
0
      break;
205
14.7k
  }
206
14.7k
}
207
208
2.30M
void FLACParser::errorCallback(FLAC__StreamDecoderErrorStatus status) {
209
2.30M
  mErrorStatus = status;
210
2.30M
}
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
11.9k
                                        unsigned nSamples, unsigned nChannels) {
234
9.88M
  for (unsigned i = 0; i < nSamples; ++i) {
235
20.5M
    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.6M
      memcpy(dst, &(src[c][i]), bytesPerSample);
240
10.6M
      dst = dst + bytesPerSample;
241
10.6M
    }
242
9.87M
  }
243
11.9k
}
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.23k
    : mDataSource(source),
255
6.23k
      mCopy(copyTrespass),
256
      mDecoder(NULL),
257
6.23k
      mCurrentPos(0LL),
258
6.23k
      mEOF(false),
259
6.23k
      mStreamInfoValid(false),
260
      mSeekTable(NULL),
261
6.23k
      firstFrameOffset(0LL),
262
6.23k
      mVorbisCommentsValid(false),
263
6.23k
      mPicturesValid(false),
264
6.23k
      mWriteRequested(false),
265
6.23k
      mWriteCompleted(false),
266
      mWriteBuffer(NULL),
267
6.23k
      mErrorStatus((FLAC__StreamDecoderErrorStatus)-1) {
268
6.23k
  memset(&mStreamInfo, 0, sizeof(mStreamInfo));
269
6.23k
  memset(&mWriteHeader, 0, sizeof(mWriteHeader));
270
6.23k
}
271
272
6.23k
FLACParser::~FLACParser() {
273
6.23k
  if (mDecoder != NULL) {
274
6.23k
    FLAC__stream_decoder_delete(mDecoder);
275
6.23k
    mDecoder = NULL;
276
6.23k
  }
277
6.23k
}
278
279
6.23k
bool FLACParser::init() {
280
  // setup libFLAC parser
281
6.23k
  mDecoder = FLAC__stream_decoder_new();
282
6.23k
  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.23k
  FLAC__stream_decoder_set_md5_checking(mDecoder, false);
289
6.23k
  FLAC__stream_decoder_set_metadata_ignore_all(mDecoder);
290
6.23k
  FLAC__stream_decoder_set_metadata_respond(mDecoder,
291
6.23k
                                            FLAC__METADATA_TYPE_STREAMINFO);
292
6.23k
  FLAC__stream_decoder_set_metadata_respond(mDecoder,
293
6.23k
                                            FLAC__METADATA_TYPE_SEEKTABLE);
294
6.23k
  FLAC__stream_decoder_set_metadata_respond(mDecoder,
295
6.23k
                                            FLAC__METADATA_TYPE_VORBIS_COMMENT);
296
6.23k
  FLAC__stream_decoder_set_metadata_respond(mDecoder,
297
6.23k
                                            FLAC__METADATA_TYPE_PICTURE);
298
6.23k
  FLAC__StreamDecoderInitStatus initStatus;
299
6.23k
  initStatus = FLAC__stream_decoder_init_stream(
300
6.23k
      mDecoder, read_callback, seek_callback, tell_callback, length_callback,
301
6.23k
      eof_callback, write_callback, metadata_callback, error_callback,
302
6.23k
      reinterpret_cast<void *>(this));
303
6.23k
  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.23k
  return true;
309
6.23k
}
310
311
6.23k
bool FLACParser::decodeMetadata() {
312
  // parse all metadata
313
6.23k
  if (!FLAC__stream_decoder_process_until_end_of_metadata(mDecoder)) {
314
1.28k
    return false;
315
1.28k
  }
316
  // store first frame offset
317
4.94k
  FLAC__stream_decoder_get_decode_position(mDecoder, &firstFrameOffset);
318
319
4.94k
  if (mStreamInfoValid) {
320
    // check channel count
321
4.90k
    if (getChannels() == 0 || getChannels() > 8) {
322
0
      return false;
323
0
    }
324
    // check bit depth
325
4.90k
    switch (getBitsPerSample()) {
326
1.13k
      case 8:
327
2.05k
      case 16:
328
2.30k
      case 24:
329
4.83k
      case 32:
330
4.83k
        break;
331
67
      default:
332
67
        return false;
333
4.90k
    }
334
    // configure the appropriate copy function based on device endianness.
335
4.83k
    if (isBigEndian()) {
336
0
      mCopy = copyToByteArrayBigEndian;
337
4.83k
    } else {
338
4.83k
      mCopy = copyToByteArrayLittleEndian;
339
4.83k
    }
340
4.83k
  } else {
341
44
    return false;
342
44
  }
343
4.83k
  return true;
344
4.94k
}
345
346
16.7k
size_t FLACParser::readBuffer(void *output, size_t output_size) {
347
16.7k
  mWriteRequested = true;
348
16.7k
  mWriteCompleted = false;
349
350
16.7k
  if (!FLAC__stream_decoder_process_single(mDecoder)) {
351
856
    return -1;
352
856
  }
353
15.9k
  if (!mWriteCompleted) {
354
3.74k
    if (FLAC__stream_decoder_get_state(mDecoder) !=
355
3.74k
        FLAC__STREAM_DECODER_END_OF_STREAM) {
356
0
    }
357
3.74k
    return -1;
358
3.74k
  }
359
360
  // verify that block header keeps the promises made by STREAMINFO
361
12.1k
  unsigned blocksize = mWriteHeader.blocksize;
362
12.1k
  if (blocksize == 0 || blocksize > getMaxBlockSize()) {
363
56
    return -1;
364
56
  }
365
12.1k
  if (mWriteHeader.sample_rate != getSampleRate() ||
366
12.1k
      mWriteHeader.channels != getChannels() ||
367
12.1k
      mWriteHeader.bits_per_sample != getBitsPerSample()) {
368
161
    return -1;
369
161
  }
370
371
11.9k
  unsigned bytesPerSample = getBitsPerSample() >> 3;
372
11.9k
  size_t bufferSize = blocksize * getChannels() * bytesPerSample;
373
11.9k
  if (bufferSize > output_size) {
374
17
    return -1;
375
17
  }
376
377
  // copy PCM from FLAC write buffer to our media buffer, with interleaving.
378
11.9k
  (*mCopy)(reinterpret_cast<int8_t *>(output), mWriteBuffer, bytesPerSample,
379
11.9k
           blocksize, getChannels());
380
381
  // fill in buffer metadata
382
11.9k
  CHECK(mWriteHeader.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
383
384
11.9k
  return bufferSize;
385
11.9k
}
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.23k
    FuzzDataSource(const uint8_t *data, size_t size) {
438
6.23k
      data_ = data;
439
6.23k
      size_ = size;
440
6.23k
    }
441
442
109k
    ssize_t readAt(off64_t offset, void *const data, size_t size) {
443
109k
      if (offset > size_)
444
0
        return -1;
445
109k
      size_t remaining = size_ - offset;
446
109k
      if (remaining < size)
447
70.6k
        size = remaining;
448
109k
      memcpy(data, data_ + offset, size);
449
109k
      return size;
450
109k
    }
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.23k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
458
6.23k
  FuzzDataSource source(data, size);
459
6.23k
  FLACParser parser(&source);
460
461
  // Early parsing
462
6.23k
  if (!parser.init() || !parser.decodeMetadata())
463
1.39k
    return 0;
464
465
4.83k
  auto streamInfo = parser.getStreamInfo();
466
467
  // Similar implementation than ExoPlayer
468
4.83k
  int buffer_size = streamInfo.max_blocksize * streamInfo.channels * 2;
469
4.83k
  assert(buffer_size >= 0);  // Not expected
470
4.83k
  auto buffer = new uint8_t[buffer_size];
471
472
16.7k
  while (parser.readBuffer(buffer, buffer_size) < ((size_t)-1));
473
4.83k
  delete[] buffer;
474
475
4.83k
  return 0;
476
4.83k
}