fix moonfire_ffmpeg::Error formatting

This would return a string with trailing nuls up to the buffer size (64
bytes) which would cause problems later. One in particular: in
"moonfire-nvr config", if testing a camera failed, displaying the error would
panic with the backtrace below.

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: NulError(33, [69, 114, 114, 111, 114, 58, 32, 102, 102, 109, 112, 101, 103, 58, 32, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 32, 114, 101, 102, 117, 115, 101, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])', src/libcore/result.rs:860:4
stack backtrace:
   0: std::sys:👿:backtrace::tracing:👿:unwind_backtrace
   1: std::panicking::default_hook::{{closure}}
   2: std::panicking::default_hook
   3: std::panicking::rust_panic_with_hook
   4: std::panicking::begin_panic_new
   5: std::panicking::begin_panic_fmt
   6: rust_begin_unwind
   7: core::panicking::panic_fmt
   8: core::result::unwrap_failed
   9: <core::result::Result<T, E>>::unwrap
  10: <&'a str as ncurses::ToCStr>::to_c_str
  11: ncurses::addstr
  12: ncurses::mvaddstr
  13: <cursive::backend::curses::n::Concrete as cursive::backend::Backend>::print_at
  14: cursive:🖨️:Printer::print
  15: <cursive::views::text_view::TextView as cursive::view::View>::draw::{{closure}}
  16: cursive::view:📜:ScrollBase::draw
  17: <cursive::views::text_view::TextView as cursive::view::View>::draw
  18: <cursive::views::dialog::Dialog as cursive::view::View>::draw
  19: <cursive::views::layer::Layer<T> as cursive::view::view_wrapper::ViewWrapper>::wrap_draw
  20: cursive::view::view_wrapper::<impl cursive::view::View for T>::draw
  21: <cursive::views::shadow_view::ShadowView<T> as cursive::view::view_wrapper::ViewWrapper>::wrap_draw
  22: cursive::view::view_wrapper::<impl cursive::view::View for T>::draw
  23: <cursive::views::stack_view::StackView as cursive::view::View>::draw::{{closure}}
  24: cursive:🖨️:Printer::with_color::{{closure}}
  25: <cursive::backend::curses::n::Concrete as cursive::backend::Backend>::with_color
  26: cursive:🖨️:Printer::with_color
  27: <cursive::views::stack_view::StackView as cursive::view::View>::draw
  28: cursive::Cursive::draw
  29: cursive::Cursive::step
  30: cursive::Cursive::run
  31: moonfire_nvr::cmds::config::run
  32: moonfire_nvr::cmds::Command::run
  33: moonfire_nvr::main
  34: __rust_maybe_catch_panic
  35: std::rt::lang_start
  36: main
This commit is contained in:
Scott Lamb 2017-09-22 06:47:08 -07:00
parent 71e2930ced
commit 45b508dff6

View File

@ -76,7 +76,7 @@ extern "C" {
//#[link(name = "avutil")]
extern "C" {
fn avutil_version() -> libc::c_int;
fn av_strerror(e: libc::c_int, b: *mut u8, s: libc::size_t) -> libc::c_int;
fn av_strerror(e: libc::c_int, b: *mut libc::c_char, s: libc::size_t) -> libc::c_int;
fn av_dict_count(d: *const AVDictionary) -> libc::c_int;
fn av_dict_get(d: *const AVDictionary, key: *const libc::c_char, prev: *mut AVDictionaryEntry,
flags: libc::c_int) -> *mut AVDictionaryEntry;
@ -356,9 +356,13 @@ impl std::error::Error for Error {
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
const ARRAYLEN: usize = 64;
let mut buf = [0u8; ARRAYLEN];
unsafe { av_strerror(self.0, buf.as_mut_ptr(), ARRAYLEN) };
f.write_str(std::str::from_utf8(&buf).map_err(|_| fmt::Error)?)
let mut buf = [0; ARRAYLEN];
let s = unsafe {
// Note av_strerror uses strlcpy, so it guarantees a trailing NUL byte.
av_strerror(self.0, buf.as_mut_ptr(), ARRAYLEN);
CStr::from_ptr(buf.as_ptr())
};
f.write_str(&s.to_string_lossy())
}
}
@ -431,3 +435,19 @@ impl Ffmpeg {
Ffmpeg{}
}
}
#[cfg(test)]
mod tests {
use std::ffi::CString;
use super::Error;
#[test]
fn test_error() {
let eof_formatted = format!("{}", Error::eof());
assert!(eof_formatted.contains("End of file"), "eof is: {}", eof_formatted);
// Errors should be round trippable to a CString. (This will fail if they contain NUL
// bytes.)
CString::new(eof_formatted).unwrap();
}
}