m_option: correctly clamp OPT_FLOAT values

OPT_FLOAT values currently reuses OPT_DOUBLE handling, but if a
finite double value is produced which is out of the float range,
it results in UB.

If the floating point implementation is IEEE-754, then the value is
converted to infinity and stored in the float. However, this still
does not work as intended, as infinity is rejected for OPT_DOUBLE
unless infinity is explicitly specified as the min/max range.

Fix this by adding another clamping stage after operating the values
as double. Finite double values are clamped between FLT_MIN and
FLT_MAX, and out of range error is signaled when suitable.
This commit is contained in:
nanahi
2025-01-20 21:27:31 -05:00
committed by Dudemanguy
parent 0903e9fbd4
commit 0e7f9c39dc
+29
View File
@@ -1137,11 +1137,36 @@ const m_option_type_t m_option_type_aspect = {
#undef VAL
#define VAL(x) (*(float *)(x))
static int clamp_float(const m_option_t *opt, double *val)
{
double v = *val;
int r = clamp_double(opt, &v);
// Handle the case where range is not set and v is finite
// but overflows the float range.
if (isfinite(v) && v > FLT_MAX) {
v = FLT_MAX;
r = M_OPT_OUT_OF_RANGE;
}
if (isfinite(v) && v < FLT_MIN) {
v = FLT_MIN;
r = M_OPT_OUT_OF_RANGE;
}
*val = v;
return r;
}
static int parse_float(struct mp_log *log, const m_option_t *opt,
struct bstr name, struct bstr param, void *dst)
{
double tmp;
int r = parse_double(log, opt, name, param, &tmp);
if (r == 1 && clamp_float(opt, &tmp) < 0) {
mp_err(log, "The %.*s option is out of range: %.*s\n",
BSTR_P(name), BSTR_P(param));
return M_OPT_OUT_OF_RANGE;
}
if (r == 1 && dst)
VAL(dst) = tmp;
return r;
@@ -1163,6 +1188,7 @@ static void add_float(const m_option_t *opt, void *val, double add, bool wrap)
{
double tmp = VAL(val);
add_double(opt, &tmp, add, wrap);
clamp_float(opt, &tmp);
VAL(val) = tmp;
}
@@ -1170,6 +1196,7 @@ static void multiply_float(const m_option_t *opt, void *val, double f)
{
double tmp = VAL(val);
multiply_double(opt, &tmp, f);
clamp_float(opt, &tmp);
VAL(val) = tmp;
}
@@ -1177,6 +1204,8 @@ static int float_set(const m_option_t *opt, void *dst, struct mpv_node *src)
{
double tmp;
int r = double_set(opt, &tmp, src);
if (r >= 0 && clamp_double(opt, &tmp) < 0)
return M_OPT_OUT_OF_RANGE;
if (r >= 0)
VAL(dst) = tmp;
return r;