meh / rust-ffmpeg

Safe FFmpeg wrapper.
Do What The F*ck You Want To Public License
459 stars 97 forks source link

Potential unsoundness in `custom_channels_unchecked` #183

Closed xd009642 closed 4 months ago

xd009642 commented 4 months ago

So I got this stack trace in CI. Still have to investigate it but I can't see this code exceeding isize

ffmpeg 7:6.0

thread '<unnamed>' panicked at library/core/src/panicking.rs:156:5:
unsafe precondition(s) violated: slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`
stack backtrace:
   0: rust_begin_unwind
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/panicking.rs:645:5
   1: core::panicking::panic_nounwind_fmt::runtime
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/panicking.rs:110:18
   2: core::panicking::panic_nounwind_fmt
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/panicking.rs:123:9
   3: core::panicking::panic_nounwind
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/panicking.rs:156:5
   4: core::slice::raw::from_raw_parts::precondition_check
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/intrinsics.rs:2799:21
   5: core::slice::raw::from_raw_parts
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/slice/raw.rs:98:9
   6: ffmpeg::util::channel_layout::ChannelLayout::custom_channels_unchecked
             at /github/home/.cargo/git/checkouts/rust-ffmpeg-9e0ba839e85456a1/7c354aa/src/util/channel_layout.rs:300:3
   7: ffmpeg::util::channel_layout::ChannelLayout::custom_channels
             at /github/home/.cargo/git/checkouts/rust-ffmpeg-9e0ba839e85456a1/7c354aa/src/util/channel_layout.rs:304:80
   8: <ffmpeg::util::channel_layout::ChannelLayout as core::fmt::Debug>::fmt
             at /github/home/.cargo/git/checkouts/rust-ffmpeg-9e0ba839e85456a1/7c354aa/src/util/channel_layout.rs:401:25

https://github.com/meh/rust-ffmpeg/blob/master/src/util/channel_layout.rs#L299-L301

Our code in question processing a s16 single channel wave file looks like this:

        let input = self
            .format_context
            .streams()
            .best(media::Type::Audio)
            .ok_or(TranscodingError::NoAudio)?;
        let mut audio_decoder = input
            .decoder()
            .map_err(|e| {
                error!("Unable to create decoder: {}", e);
                TranscodingError::Unknown("Unable to create decoder".to_string())
            })?
            .audio() // <- this opens the codec
            .map_err(|_| TranscodingError::NoAudio)?;

        trace!("Layout: {:?}", audio_decoder.channel_layout()); // Causes the backtrace by panicking!
xd009642 commented 4 months ago

Well I've managed to make a MRE much easier than I anticipated:

use ffmpeg::ChannelLayout;

fn main() {
    let layout = ChannelLayout::MONO;
    println!("{:?}", layout);
}
thread 'main' panicked at library/core/src/panicking.rs:156:5:
unsafe precondition(s) violated: slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`
stack backtrace:
   0: rust_begin_unwind
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/panicking.rs:645:5
   1: core::panicking::panic_nounwind_fmt::runtime
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/panicking.rs:110:18
   2: core::panicking::panic_nounwind_fmt
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/panicking.rs:123:9
   3: core::panicking::panic_nounwind
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/panicking.rs:156:5
   4: core::slice::raw::from_raw_parts::precondition_check
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/intrinsics.rs:2799:21
   5: core::slice::raw::from_raw_parts
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/slice/raw.rs:98:9
   6: ffmpeg::util::channel_layout::ChannelLayout::custom_channels_unchecked
             at /root/.cargo/git/checkouts/rust-ffmpeg-9e0ba839e85456a1/7c354aa/src/util/channel_layout.rs:300:3
   7: ffmpeg::util::channel_layout::ChannelLayout::custom_channels
             at /root/.cargo/git/checkouts/rust-ffmpeg-9e0ba839e85456a1/7c354aa/src/util/channel_layout.rs:304:80
   8: <ffmpeg::util::channel_layout::ChannelLayout as core::fmt::Debug>::fmt
             at /root/.cargo/git/checkouts/rust-ffmpeg-9e0ba839e85456a1/7c354aa/src/util/channel_layout.rs:401:25
   9: core::fmt::rt::Argument::fmt
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/fmt/rt.rs:142:9
  10: core::fmt::write
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/fmt/mod.rs:1153:17
  11: std::io::Write::write_fmt
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/io/mod.rs:1843:15
  12: <&std::io::stdio::Stdout as std::io::Write>::write_fmt
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/io/stdio.rs:776:9
  13: <std::io::stdio::Stdout as std::io::Write>::write_fmt
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/io/stdio.rs:750:9
  14: std::io::stdio::print_to
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/io/stdio.rs:1087:21
  15: std::io::stdio::_print
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/io/stdio.rs:1164:5
  16: segfaulter::main
             at ./examples/segfaulter.rs:5:5
  17: core::ops::function::FnOnce::call_once
             at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
thread caused non-unwinding panic. aborting.
Aborted (core dumped)
nitroxis commented 4 months ago

I've encountered a similar issue in the read_packet wrapper. It seems like ffmpeg calls that method with buf = null and size = 0 under certain circumstances (what those are I don't know).

unsafe precondition(s) violated: slice::from_raw_parts_mut requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`
   0: rust_begin_unwind
             at /rustc/129f3b9964af4d4a709d1383930ade12dfe7c081/library/std/src/panicking.rs:652:5
   1: core::panicking::panic_nounwind_fmt::runtime
             at /rustc/129f3b9964af4d4a709d1383930ade12dfe7c081/library/core/src/panicking.rs:110:18
   2: core::panicking::panic_nounwind_fmt
             at /rustc/129f3b9964af4d4a709d1383930ade12dfe7c081/library/core/src/panicking.rs:120:5
   3: core::panicking::panic_nounwind
             at /rustc/129f3b9964af4d4a709d1383930ade12dfe7c081/library/core/src/panicking.rs:220:5
   4: core::slice::raw::from_raw_parts_mut::precondition_check
             at /rustc/129f3b9964af4d4a709d1383930ade12dfe7c081/library/core/src/ub_checks.rs:66:21
   5: core::slice::raw::from_raw_parts_mut
             at /rustc/129f3b9964af4d4a709d1383930ade12dfe7c081/library/core/src/ub_checks.rs:73:17
   6: ffmpeg::format::io::read_packet
             at ~/.cargo/git/checkouts/rust-ffmpeg-9e0ba839e85456a1/7c354aa/src/format/io.rs:81:15
   7: avio_feof
   8: avio_read
   9: av_probe_input_buffer2
  10: avformat_open_input
  11: ffmpeg::format::io::input
             at ~/.cargo/git/checkouts/rust-ffmpeg-9e0ba839e85456a1/7c354aa/src/format/io.rs:222:9