Coverage Report

Created: 2025-07-01 06:50

/rust/registry/src/index.crates.io-6f17d22bba15001f/rav1e-0.7.1/src/fuzzing.rs
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2019-2022, The rav1e contributors. All rights reserved
2
//
3
// This source code is subject to the terms of the BSD 2 Clause License and
4
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
5
// was not distributed with this source code in the LICENSE file, you can
6
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
7
// Media Patent License 1.0 was not distributed with this source code in the
8
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.
9
10
use std::marker::PhantomData;
11
use std::sync::Arc;
12
13
use libfuzzer_sys::arbitrary::{Arbitrary, Error, Unstructured};
14
15
use crate::prelude::*;
16
17
// Adding new fuzz targets
18
//
19
// 1. Add a function to this file which looks like this:
20
//
21
//    pub fn fuzz_something(data: Data) {
22
//      // Invoke everything you need.
23
//      //
24
//      // Your function may accept a value of any type that implements
25
//      // Arbitrary [1]. This is how fuzzer affects the execution—by
26
//      // feeding in different bytes, which result in different
27
//      // arbitrary values being generated.
28
//      // [1]: https://docs.rs/arbitrary/0.3.3/arbitrary/trait.Arbitrary.html
29
//      //
30
//      // Derive Debug for the structures you create with arbitrary data.
31
//    }
32
//
33
// 2. cargo fuzz add something
34
// 3. Copy the contents of any other .rs file from fuzz/fuzz_targets/ into the
35
//    newly created fuzz/fuzz_targets/something.rs and change the function
36
//    being called to fuzz_something.
37
//
38
// Now you can fuzz the new target with cargo fuzz.
39
40
#[derive(Debug)]
41
pub struct ArbitraryConfig {
42
  config: Config,
43
}
44
45
#[inline]
46
0
fn arbitrary_rational(u: &mut Unstructured<'_>) -> Result<Rational, Error> {
47
0
  Ok(Rational::new(Arbitrary::arbitrary(u)?, Arbitrary::arbitrary(u)?))
48
0
}
49
50
#[inline]
51
0
fn arbitrary_color_description(
52
0
  u: &mut Unstructured<'_>,
53
0
) -> Result<Option<ColorDescription>, Error> {
54
0
  if Arbitrary::arbitrary(u)? {
55
0
    return Ok(None);
56
0
  }
57
0
  Ok(Some(ColorDescription {
58
0
    color_primaries: *u.choose(&[
59
0
      ColorPrimaries::BT709,
60
0
      ColorPrimaries::Unspecified,
61
0
      ColorPrimaries::BT470M,
62
0
      ColorPrimaries::BT470BG,
63
0
      ColorPrimaries::BT601,
64
0
      ColorPrimaries::SMPTE240,
65
0
      ColorPrimaries::GenericFilm,
66
0
      ColorPrimaries::BT2020,
67
0
      ColorPrimaries::XYZ,
68
0
      ColorPrimaries::SMPTE431,
69
0
      ColorPrimaries::SMPTE432,
70
0
      ColorPrimaries::EBU3213,
71
0
    ])?,
72
0
    transfer_characteristics: *u.choose(&[
73
0
      TransferCharacteristics::BT709,
74
0
      TransferCharacteristics::Unspecified,
75
0
      TransferCharacteristics::BT470M,
76
0
      TransferCharacteristics::BT470BG,
77
0
      TransferCharacteristics::BT601,
78
0
      TransferCharacteristics::SMPTE240,
79
0
      TransferCharacteristics::Linear,
80
0
      TransferCharacteristics::Log100,
81
0
      TransferCharacteristics::Log100Sqrt10,
82
0
      TransferCharacteristics::IEC61966,
83
0
      TransferCharacteristics::BT1361,
84
0
      TransferCharacteristics::SRGB,
85
0
      TransferCharacteristics::BT2020_10Bit,
86
0
      TransferCharacteristics::BT2020_12Bit,
87
0
      TransferCharacteristics::SMPTE2084,
88
0
      TransferCharacteristics::SMPTE428,
89
0
      TransferCharacteristics::HLG,
90
0
    ])?,
91
0
    matrix_coefficients: *u.choose(&[
92
0
      MatrixCoefficients::Identity,
93
0
      MatrixCoefficients::BT709,
94
0
      MatrixCoefficients::Unspecified,
95
0
      MatrixCoefficients::FCC,
96
0
      MatrixCoefficients::BT470BG,
97
0
      MatrixCoefficients::BT601,
98
0
      MatrixCoefficients::SMPTE240,
99
0
      MatrixCoefficients::YCgCo,
100
0
      MatrixCoefficients::BT2020NCL,
101
0
      MatrixCoefficients::BT2020CL,
102
0
      MatrixCoefficients::SMPTE2085,
103
0
      MatrixCoefficients::ChromatNCL,
104
0
      MatrixCoefficients::ChromatCL,
105
0
      MatrixCoefficients::ICtCp,
106
0
    ])?,
107
  }))
108
0
}
109
110
#[inline]
111
0
fn arbitrary_chromacity_point(
112
0
  u: &mut Unstructured<'_>,
113
0
) -> Result<ChromaticityPoint, Error> {
114
0
  Ok(ChromaticityPoint {
115
0
    x: Arbitrary::arbitrary(u)?,
116
0
    y: Arbitrary::arbitrary(u)?,
117
  })
118
0
}
119
120
#[inline]
121
0
fn arbitrary_mastering_display(
122
0
  u: &mut Unstructured<'_>,
123
0
) -> Result<Option<MasteringDisplay>, Error> {
124
0
  if Arbitrary::arbitrary(u)? {
125
0
    return Ok(None);
126
0
  }
127
0
  Ok(Some(MasteringDisplay {
128
0
    primaries: [
129
0
      arbitrary_chromacity_point(u)?,
130
0
      arbitrary_chromacity_point(u)?,
131
0
      arbitrary_chromacity_point(u)?,
132
    ],
133
0
    white_point: arbitrary_chromacity_point(u)?,
134
0
    max_luminance: Arbitrary::arbitrary(u)?,
135
0
    min_luminance: Arbitrary::arbitrary(u)?,
136
  }))
137
0
}
138
139
#[inline]
140
0
fn arbitrary_content_light(
141
0
  u: &mut Unstructured<'_>,
142
0
) -> Result<Option<ContentLight>, Error> {
143
0
  if Arbitrary::arbitrary(u)? {
144
0
    return Ok(None);
145
0
  }
146
0
  Ok(Some(ContentLight {
147
0
    max_content_light_level: Arbitrary::arbitrary(u)?,
148
0
    max_frame_average_light_level: Arbitrary::arbitrary(u)?,
149
  }))
150
0
}
151
152
impl Arbitrary<'_> for ArbitraryConfig {
153
0
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
154
0
    let mut enc = EncoderConfig::with_speed_preset(Arbitrary::arbitrary(u)?);
155
0
    enc.width = Arbitrary::arbitrary(u)?;
156
0
    enc.height = Arbitrary::arbitrary(u)?;
157
0
    enc.bit_depth = u.int_in_range(0..=16)?;
158
0
    enc.still_picture = Arbitrary::arbitrary(u)?;
159
0
    enc.time_base = arbitrary_rational(u)?;
160
0
    enc.min_key_frame_interval = Arbitrary::arbitrary(u)?;
161
0
    enc.max_key_frame_interval = Arbitrary::arbitrary(u)?;
162
0
    enc.reservoir_frame_delay = Arbitrary::arbitrary(u)?;
163
0
    enc.low_latency = Arbitrary::arbitrary(u)?;
164
0
    enc.quantizer = Arbitrary::arbitrary(u)?;
165
0
    enc.min_quantizer = Arbitrary::arbitrary(u)?;
166
0
    enc.bitrate = Arbitrary::arbitrary(u)?;
167
0
    enc.tile_cols = Arbitrary::arbitrary(u)?;
168
0
    enc.tile_rows = Arbitrary::arbitrary(u)?;
169
0
    enc.tiles = Arbitrary::arbitrary(u)?;
170
0
    enc.speed_settings.rdo_lookahead_frames = Arbitrary::arbitrary(u)?;
171
0
    let config = Config::new().with_encoder_config(enc).with_threads(1);
172
0
    Ok(Self { config })
173
0
  }
174
}
175
176
0
pub fn fuzz_construct_context(arbitrary: ArbitraryConfig) {
177
0
  let _: Result<Context<u16>, _> = arbitrary.config.new_context();
178
0
}
179
180
0
fn encode_frames(
181
0
  ctx: &mut Context<u8>, mut frames: impl Iterator<Item = Frame<u8>>,
182
0
) -> Result<(), EncoderStatus> {
183
  loop {
184
0
    let rv = ctx.receive_packet();
185
0
    debug!("ctx.receive_packet() = {:#?}", rv);
186
187
0
    match rv {
188
0
      Ok(_packet) => {}
189
0
      Err(EncoderStatus::Encoded) => {}
190
      Err(EncoderStatus::LimitReached) => {
191
0
        break;
192
      }
193
      Err(EncoderStatus::NeedMoreData) => {
194
0
        ctx.send_frame(frames.next().map(Arc::new))?;
195
      }
196
      Err(EncoderStatus::EnoughData) => {
197
0
        unreachable!();
198
      }
199
      Err(EncoderStatus::NotReady) => {
200
0
        unreachable!();
201
      }
202
      Err(EncoderStatus::Failure) => {
203
0
        return Err(EncoderStatus::Failure);
204
      }
205
    }
206
  }
207
208
0
  Ok(())
209
0
}
210
211
#[derive(Debug)]
212
pub struct ArbitraryEncoder {
213
  config: Config,
214
  frame_count: u8,
215
  pixels: Box<[u8]>,
216
}
217
218
impl Arbitrary<'_> for ArbitraryEncoder {
219
0
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
220
0
    let enc = EncoderConfig {
221
0
      speed_settings: SpeedSettings::from_preset(u.int_in_range(0..=10)?),
222
0
      width: u.int_in_range(1..=256)?,
223
0
      height: u.int_in_range(1..=256)?,
224
0
      still_picture: Arbitrary::arbitrary(u)?,
225
0
      time_base: arbitrary_rational(u)?,
226
0
      min_key_frame_interval: u.int_in_range(0..=3)?,
227
0
      max_key_frame_interval: u.int_in_range(1..=4)?,
228
0
      low_latency: Arbitrary::arbitrary(u)?,
229
0
      quantizer: Arbitrary::arbitrary(u)?,
230
0
      min_quantizer: Arbitrary::arbitrary(u)?,
231
0
      bitrate: Arbitrary::arbitrary(u)?,
232
0
      tile_cols: u.int_in_range(0..=2)?,
233
0
      tile_rows: u.int_in_range(0..=2)?,
234
0
      tiles: u.int_in_range(0..=16)?,
235
236
0
      chroma_sampling: *u.choose(&[
237
0
        ChromaSampling::Cs420,
238
0
        ChromaSampling::Cs422,
239
0
        ChromaSampling::Cs444,
240
0
        ChromaSampling::Cs400,
241
0
      ])?,
242
0
      chroma_sample_position: *u.choose(&[
243
0
        ChromaSamplePosition::Unknown,
244
0
        ChromaSamplePosition::Vertical,
245
0
        ChromaSamplePosition::Colocated,
246
0
      ])?,
247
0
      pixel_range: *u.choose(&[PixelRange::Limited, PixelRange::Full])?,
248
0
      error_resilient: Arbitrary::arbitrary(u)?,
249
0
      reservoir_frame_delay: Arbitrary::arbitrary(u)?,
250
251
0
      sample_aspect_ratio: arbitrary_rational(u)?,
252
      bit_depth: 8,
253
0
      color_description: arbitrary_color_description(u)?,
254
0
      mastering_display: arbitrary_mastering_display(u)?,
255
0
      content_light: arbitrary_content_light(u)?,
256
0
      level_idx: Some(31),
257
0
      enable_timing_info: Arbitrary::arbitrary(u)?,
258
0
      switch_frame_interval: u.int_in_range(0..=3)?,
259
0
      tune: *u.choose(&[Tune::Psnr, Tune::Psychovisual])?,
260
0
      film_grain_params: None,
261
    };
262
263
0
    let frame_count =
264
0
      if enc.still_picture { 1 } else { u.int_in_range(1..=3)? };
265
0
    if u.is_empty() {
266
0
      return Err(Error::NotEnoughData);
267
0
    }
268
0
    let pixels = u.bytes(u.len())?.to_vec().into_boxed_slice();
269
0
    let config = Config::new().with_encoder_config(enc).with_threads(1);
270
0
    Ok(Self { config, frame_count, pixels })
271
0
  }
272
}
273
274
0
pub fn fuzz_encode(arbitrary: ArbitraryEncoder) {
275
0
  let res = arbitrary.config.new_context();
276
0
  if res.is_err() {
277
0
    return;
278
0
  }
279
0
  let mut context: Context<u8> = res.unwrap();
280
0
281
0
  let mut pixels = arbitrary.pixels.iter().cycle();
282
0
  let mut frame = context.new_frame();
283
0
  let frames = (0..arbitrary.frame_count).map(|_| {
284
0
    for plane in &mut frame.planes {
285
0
      let stride = plane.cfg.stride;
286
0
      for row in plane.data_origin_mut().chunks_mut(stride) {
287
0
        for pixel in row {
288
0
          *pixel = *pixels.next().unwrap();
289
0
        }
290
      }
291
    }
292
293
0
    frame.clone()
294
0
  });
295
0
296
0
  let _ = encode_frames(&mut context, frames);
297
0
}
298
299
#[derive(Debug)]
300
pub struct DecodeTestParameters<T: Pixel> {
301
  w: usize,
302
  h: usize,
303
  speed: u8,
304
  q: usize,
305
  limit: usize,
306
  bit_depth: usize,
307
  chroma_sampling: ChromaSampling,
308
  min_keyint: u64,
309
  max_keyint: u64,
310
  switch_frame_interval: u64,
311
  low_latency: bool,
312
  error_resilient: bool,
313
  bitrate: i32,
314
  tile_cols_log2: usize,
315
  tile_rows_log2: usize,
316
  still_picture: bool,
317
  pixel: PhantomData<T>,
318
}
319
320
impl<T: Pixel> Arbitrary<'_> for DecodeTestParameters<T> {
321
0
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
322
0
    let mut p = Self {
323
0
      w: u.int_in_range(16..=16 + 255)?,
324
0
      h: u.int_in_range(16..=16 + 255)?,
325
0
      speed: u.int_in_range(0..=10)?,
326
0
      q: u8::arbitrary(u)?.into(),
327
0
      limit: u.int_in_range(1..=3)?,
328
      bit_depth: 8,
329
0
      chroma_sampling: *u.choose(&[
330
0
        ChromaSampling::Cs420,
331
0
        ChromaSampling::Cs422,
332
0
        ChromaSampling::Cs444,
333
0
        ChromaSampling::Cs400,
334
0
      ])?,
335
0
      min_keyint: u.int_in_range(0..=3)?,
336
0
      max_keyint: u.int_in_range(1..=4)?,
337
0
      switch_frame_interval: u.int_in_range(0..=3)?,
338
0
      low_latency: bool::arbitrary(u)?,
339
0
      error_resilient: bool::arbitrary(u)?,
340
0
      bitrate: u16::arbitrary(u)?.into(),
341
0
      tile_cols_log2: u.int_in_range(0..=2)?,
342
0
      tile_rows_log2: u.int_in_range(0..=2)?,
343
0
      still_picture: bool::arbitrary(u)?,
344
0
      pixel: PhantomData,
345
    };
346
0
    if matches!(T::type_enum(), PixelType::U16) {
347
0
      p.bit_depth = *u.choose(&[8, 10, 12])?;
348
0
    }
349
0
    if !p.low_latency {
350
0
      p.switch_frame_interval = 0;
351
0
    }
352
0
    if p.still_picture {
353
0
      p.limit = 1
354
0
    }
355
0
    Ok(p)
356
0
  }
357
}
358
359
#[cfg(feature = "decode_test_dav1d")]
360
pub fn fuzz_encode_decode<T: Pixel>(p: DecodeTestParameters<T>) {
361
  use crate::test_encode_decode::*;
362
363
  let mut dec = get_decoder::<T>("dav1d", p.w, p.h);
364
  dec.encode_decode(
365
    true,
366
    p.w,
367
    p.h,
368
    p.speed,
369
    p.q,
370
    p.limit,
371
    p.bit_depth,
372
    p.chroma_sampling,
373
    p.min_keyint,
374
    p.max_keyint,
375
    p.switch_frame_interval,
376
    p.low_latency,
377
    p.error_resilient,
378
    p.bitrate,
379
    p.tile_cols_log2,
380
    p.tile_rows_log2,
381
    p.still_picture,
382
    None,
383
  );
384
}