Coverage Report

Created: 2025-07-18 07:02

/src/opusfile_fuzzer.c
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2020 Google LLC
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 <errno.h>
16
#include <stdint.h>
17
#include <stdio.h>
18
#include <stdlib.h>
19
#include <string.h>
20
21
#include "opusfile/config.h"
22
#include "opusfile/include/opusfile.h"
23
24
// Opusfile fuzzing wrapper to help with automated fuzz testing. It's based on
25
// https://github.com/xiph/opusfile/blob/master/examples/opusfile_example.c
26
3.31k
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
27
3.31k
  int ret, tmp;
28
3.31k
  OggOpusFile *of = op_open_memory(data, size, &ret);
29
3.31k
  if (!of)
30
857
    return 0;
31
32
2.45k
  op_link_count(of);
33
34
2.45k
  int link_index = -1;
35
2.45k
  op_pcm_total(of, link_index);
36
2.45k
  op_raw_total(of, link_index);
37
2.45k
  op_pcm_tell(of);
38
2.45k
  op_raw_tell(of);
39
40
2.45k
  ogg_int64_t total_sample_count = 0;
41
2.45k
  const int pcm_size = 120 * 48 * 2; // 120ms/ch@48kHz is recommended
42
2.45k
  opus_int16 pcm[pcm_size];
43
255k
  for (;;) {
44
255k
    ret = op_read_stereo(of, pcm, pcm_size);
45
255k
    if (ret < 0) {
46
1.52k
      break;
47
1.52k
    }
48
49
254k
    if (op_current_link(of) != link_index) {
50
8.85k
      link_index = op_current_link(of);
51
8.85k
      op_pcm_total(of, link_index);
52
8.85k
      op_raw_total(of, link_index);
53
8.85k
      op_pcm_tell(of);
54
8.85k
      op_raw_tell(of);
55
8.85k
      op_bitrate_instant(of);
56
8.85k
      tmp = op_head(of, link_index)->version;
57
58
8.85k
      const OpusTags *tags = op_tags(of, link_index);
59
15.4k
      for (int i = 0; i < tags->comments; ++i) {
60
        // Note: The compare also touches memory allocated for user_comments[i].
61
        // This is a desired side effect and should be kept even if this
62
        // comparison is removed.
63
6.61k
        if (opus_tagncompare("METADATA_BLOCK_PICTURE", 22,
64
6.61k
                             tags->user_comments[i]) == 0) {
65
0
          OpusPictureTag pic;
66
0
          if (opus_picture_tag_parse(&pic, tags->user_comments[i]) >= 0) {
67
0
            opus_picture_tag_clear(&pic);
68
0
          }
69
0
        }
70
6.61k
      }
71
72
8.85k
      if (tags->vendor) {
73
8.85k
        tmp = tags->vendor[0];
74
8.85k
      }
75
76
8.85k
      int binary_suffix_len;
77
8.85k
      opus_tags_get_binary_suffix(tags, &binary_suffix_len);
78
8.85k
    }
79
80
254k
    if (ret == 0) {
81
934
      break;
82
934
    }
83
84
253k
    total_sample_count += ret;
85
253k
  }
86
87
2.45k
  if (total_sample_count > 0) {
88
    // Try random-access PCM reads. The number of tests is arbitrary and the
89
    // offset is designed to be pseudo-random, but deterministic - this is
90
    // implemented using Lehmer RNG with a minor hack that probably breaks some
91
    // properties of the RNG (but that is acceptable).
92
2.21k
    ogg_int64_t rng_seed = 1307832949LL;
93
73.2k
    for (int i = 0; i < 32; ++i) {
94
      // Derive the next deterministic offset to test and iterate the RNG.
95
71.0k
      rng_seed = (rng_seed * 279470273LL);
96
71.0k
      const ogg_int64_t offset = rng_seed % total_sample_count;
97
71.0k
      rng_seed = rng_seed % 4294967291LL;
98
99
71.0k
      if (op_pcm_seek(of, offset) == 0) {
100
44.5k
        tmp = op_read_stereo(of, pcm, pcm_size);
101
44.5k
      }
102
71.0k
    }
103
2.21k
  }
104
105
2.45k
  op_free(of);
106
2.45k
  return 0;
107
3.31k
}