rtpgccbwe: avoid clamp() panic when min_bitrate > max_bitrate

Prevent calling clamp() with invalid bounds where min > max, which would
cause a panic with "assertion failed: min <= max". This panic would poison
the mutex lock, causing all subsequent lock().unwrap() calls to fail with
PoisonError.

This can happen when min-bitrate and max-bitrate properties are set
individually, creating a temporary inconsistent state between the values.

Fix by validating the bitrate range before calling clamp() and using
max_bitrate for both bounds when min > max to ensure safe operation.
Use LogContext to log the error only once per unique invalid pair.

Fixes #711

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/2456>
This commit is contained in:
Thibault Saunier 2025-08-11 11:12:14 -04:00
parent 2336688c8a
commit abc5cf7303

View file

@ -946,19 +946,33 @@ impl State {
) -> bool {
let prev_bitrate = Bitrate::min(self.target_bitrate_on_delay, self.target_bitrate_on_loss);
// Ensure min_bitrate <= max_bitrate to avoid panic in clamp()
let (min_bitrate, max_bitrate) = if self.min_bitrate <= self.max_bitrate {
(self.min_bitrate, self.max_bitrate)
} else {
gst::error!(
CAT,
obj = bwe,
"min_bitrate ({}) > max_bitrate ({}), using max_bitrate for both to avoid panic",
self.min_bitrate,
self.max_bitrate
);
(self.max_bitrate, self.max_bitrate)
};
match controller_type {
ControllerType::Loss => {
self.target_bitrate_on_loss = bitrate.clamp(self.min_bitrate, self.max_bitrate)
self.target_bitrate_on_loss = bitrate.clamp(min_bitrate, max_bitrate)
}
ControllerType::Delay => {
self.target_bitrate_on_delay = bitrate.clamp(self.min_bitrate, self.max_bitrate)
self.target_bitrate_on_delay = bitrate.clamp(min_bitrate, max_bitrate)
}
}
let target_bitrate =
Bitrate::min(self.target_bitrate_on_delay, self.target_bitrate_on_loss)
.clamp(self.min_bitrate, self.max_bitrate);
.clamp(min_bitrate, max_bitrate);
if target_bitrate == prev_bitrate {
return false;