gst/ClockTime: panic building from GST_CLOCK_TIME_NONE

Using `ClockTime::from_nseconds` it was possible to build a valid
`ClockTime` which would match `GST_CLOCK_TIME_NONE` when passed to
the C API, leading to unexpected behaviour as `GST_CLOCK_TIME_NONE`
is represented as an `Option::<ClockTime>::None` in Rust.

This commit panics when this function is called with
`GST_CLOCK_TIME_NONE` (defined as `u64::MAX`). This is similar to
what happens when calling other `ClockTime` constructors (e.g.
`from_seconds`) with too large a value: the internal multiplication
overflows leading to a panic.
This commit is contained in:
François Laignel 2022-09-16 15:16:49 +02:00 committed by François Laignel
parent b8e1c25c85
commit 55ef309b16

View file

@ -50,23 +50,68 @@ impl ClockTime {
self.0 self.0
} }
// rustdoc-stripper-ignore-next
/// Builds a new `ClockTime` which value is the given number of seconds.
///
/// # Panics
///
/// Panics if the resulting duration in nanoseconds exceeds the `u64` range.
#[track_caller]
pub const fn from_seconds(seconds: u64) -> Self { pub const fn from_seconds(seconds: u64) -> Self {
skip_assert_initialized!(); skip_assert_initialized!();
ClockTime(seconds * Self::SECOND.0) // `Option::expect` is not `const` as of rustc 1.63.0.
ClockTime(match seconds.checked_mul(Self::SECOND.0) {
Some(res) => res,
None => panic!("Out of `ClockTime` range"),
})
} }
// rustdoc-stripper-ignore-next
/// Builds a new `ClockTime` which value is the given number of milliseconds.
///
/// # Panics
///
/// Panics if the resulting duration in nanoseconds exceeds the `u64` range.
#[track_caller]
pub const fn from_mseconds(mseconds: u64) -> Self { pub const fn from_mseconds(mseconds: u64) -> Self {
skip_assert_initialized!(); skip_assert_initialized!();
ClockTime(mseconds * Self::MSECOND.0) // `Option::expect` is not `const` as of rustc 1.63.0.
ClockTime(match mseconds.checked_mul(Self::MSECOND.0) {
Some(res) => res,
None => panic!("Out of `ClockTime` range"),
})
} }
// rustdoc-stripper-ignore-next
/// Builds a new `ClockTime` which value is the given number of microseconds.
///
/// # Panics
///
/// Panics if the resulting duration in nanoseconds exceeds the `u64` range.
#[track_caller]
pub const fn from_useconds(useconds: u64) -> Self { pub const fn from_useconds(useconds: u64) -> Self {
skip_assert_initialized!(); skip_assert_initialized!();
ClockTime(useconds * Self::USECOND.0) // `Option::expect` is not `const` as of rustc 1.63.0.
ClockTime(match useconds.checked_mul(Self::USECOND.0) {
Some(res) => res,
None => panic!("Out of `ClockTime` range"),
})
} }
// rustdoc-stripper-ignore-next
/// Builds a new `ClockTime` which value is the given number of nanoseconds.
///
/// # Panics
///
/// Panics if the requested duration equals `GST_CLOCK_TIME_NONE`
/// (`u64::MAX`).
#[track_caller]
pub const fn from_nseconds(nseconds: u64) -> Self { pub const fn from_nseconds(nseconds: u64) -> Self {
skip_assert_initialized!(); skip_assert_initialized!();
assert!(
nseconds != ffi::GST_CLOCK_TIME_NONE,
"Attempt to build a `ClockTime` with value `GST_CLOCK_TIME_NONE`",
);
ClockTime(nseconds * Self::NSECOND.0) ClockTime(nseconds * Self::NSECOND.0)
} }
} }
@ -113,7 +158,7 @@ impl glib::value::ToValue for ClockTime {
if gct == ffi::GST_CLOCK_TIME_NONE { if gct == ffi::GST_CLOCK_TIME_NONE {
crate::warning!( crate::warning!(
crate::CAT_RUST, crate::CAT_RUST,
"converting a defined `ClockTime` with value `ffi::GST_CLOCK_TIME_NONE` to `Value`, this is probably not what you wanted.", "converting a defined `ClockTime` with value `GST_CLOCK_TIME_NONE` to `Value`, this is probably not what you wanted.",
); );
} }
unsafe { glib::gobject_ffi::g_value_set_uint64(value.to_glib_none_mut().0, gct) } unsafe { glib::gobject_ffi::g_value_set_uint64(value.to_glib_none_mut().0, gct) }
@ -864,4 +909,16 @@ mod tests {
.sum(); .sum();
assert_eq!(s, ClockTime::from_seconds(3)); assert_eq!(s, ClockTime::from_seconds(3));
} }
#[test]
#[should_panic]
fn attempt_to_build_from_clock_time_none() {
let _ = ClockTime::from_nseconds(ffi::GST_CLOCK_TIME_NONE);
}
#[test]
#[should_panic]
fn attempt_to_build_from_u64max() {
let _ = ClockTime::from_nseconds(u64::MAX);
}
} }