From 84928b1fb100004686ac61851720da9247cad34b Mon Sep 17 00:00:00 2001 From: Oleg Oshmyan Date: Sat, 10 Oct 2020 02:07:42 +0300 Subject: Factor out & improve UB-less double -> int32_t conversion The value may be bigger than INT32_MAX as long as its *integral part* isn't. Furthermore, make sure to avoid UB on odd platforms where int32_t limits aren't exactly representable in double, as this isn't too hard. Do assume that they're representable at all though. We won't necessarily match x86 values on such platforms, but we will avoid the undefined behavior. --- libass/ass_parse.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/libass/ass_parse.c b/libass/ass_parse.c index 935dbb0..b40cc33 100644 --- a/libass/ass_parse.c +++ b/libass/ass_parse.c @@ -128,6 +128,17 @@ void update_font(ASS_Renderer *render_priv) render_priv->state.font = ass_font_new(render_priv, &desc); } +/** + * \brief Convert double to int32_t without UB + * on out-of-range values; match x86 behavior + */ +static inline int32_t dtoi32(double val) +{ + if (isnan(val) || val <= INT32_MIN || val >= INT32_MAX + 1LL) + return INT32_MIN; + return val; +} + static double calc_anim(double new, double old, double pwr) { return (1 - pwr) * old + new * pwr; @@ -135,13 +146,7 @@ static double calc_anim(double new, double old, double pwr) static int32_t calc_anim_int32(uint32_t new, uint32_t old, double pwr) { - double ret = calc_anim(new, old, pwr); - - // Avoid UB on out-of-range values; match x86 behavior - if (isnan(ret) || ret < INT32_MIN || ret > INT32_MAX) - return INT32_MIN; - - return ret; + return dtoi32(calc_anim(new, old, pwr)); } /** -- cgit v1.2.3