From ea346a23de428930fcd9cc0666150f35e04cb902 Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt Date: Wed, 1 Oct 2025 07:56:49 +0200 Subject: [PATCH] avfilter/blend_modes: Use stride in bytes The blend functions currently convert strides from bytes to elements of the type by using the stride /= sizeof(pixel) idiom. Yet this has several drawbacks: 1. It invokes undefined behavior that happens to work when stride is negative: size_t is typically the unsigned type of ptrdiff_t and therefore the division will be performed as size_t, i.e. use logical right shifts, making stride very big when sizeof(pixel) is > 1. This works, because pointer to pixel for accesses entails an implicit factor of sizeof(pixel) so that everything is correct modulo SIZE_MAX. Yet this is UB and UBSan complains about it. 2. It makes the compiler emit actual shifts/ands to discard the low bits shifted away. 3. There may be systems where alignof(uint16_t) or alignof(float) is strictly smaller than their sizeof, so that the stride (in bytes) is not guaranteed to be multiple of these sizeofs. In this case, dividing by sizeof(pixel) is simply wrong. Signed-off-by: Andreas Rheinhardt --- libavfilter/blend_modes.c | 16 ++++++---------- libavfilter/vf_blend_init.h | 16 ++++++---------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/libavfilter/blend_modes.c b/libavfilter/blend_modes.c index 9b1e78b146..35e365996c 100644 --- a/libavfilter/blend_modes.c +++ b/libavfilter/blend_modes.c @@ -92,22 +92,18 @@ static void fn0(NAME)(const uint8_t *_top, ptrdiff_t top_linesize, \ ptrdiff_t width, ptrdiff_t height, \ FilterParams *param, SliceParams *sliceparam) \ { \ - const PIXEL *top = (const PIXEL *)_top; \ - const PIXEL *bottom = (const PIXEL *)_bottom; \ - PIXEL *dst = (PIXEL *)_dst; \ const float opacity = param->opacity; \ \ - dst_linesize /= sizeof(PIXEL); \ - top_linesize /= sizeof(PIXEL); \ - bottom_linesize /= sizeof(PIXEL); \ - \ for (int i = 0; i < height; i++) { \ + const PIXEL *top = (const PIXEL *)_top; \ + const PIXEL *bottom = (const PIXEL *)_bottom; \ + PIXEL *dst = (PIXEL *)_dst; \ for (int j = 0; j < width; j++) { \ dst[j] = top[j] + ((EXPR)-top[j]) * opacity; \ } \ - dst += dst_linesize; \ - top += top_linesize; \ - bottom += bottom_linesize; \ + _dst += dst_linesize; \ + _top += top_linesize; \ + _bottom += bottom_linesize; \ } \ } diff --git a/libavfilter/vf_blend_init.h b/libavfilter/vf_blend_init.h index 98d440fe67..7f66796e3e 100644 --- a/libavfilter/vf_blend_init.h +++ b/libavfilter/vf_blend_init.h @@ -82,22 +82,18 @@ static void blend_normal_##name(const uint8_t *_top, ptrdiff_t top_linesize, ptrdiff_t width, ptrdiff_t height, \ FilterParams *param, SliceParams *sliceparam) \ { \ - const type *top = (const type*)_top; \ - const type *bottom = (const type*)_bottom; \ - type *dst = (type*)_dst; \ const float opacity = param->opacity; \ \ - dst_linesize /= sizeof(type); \ - top_linesize /= sizeof(type); \ - bottom_linesize /= sizeof(type); \ - \ for (int i = 0; i < height; i++) { \ + const type *top = (const type*)_top; \ + const type *bottom = (const type*)_bottom; \ + type *dst = (type*)_dst; \ for (int j = 0; j < width; j++) { \ dst[j] = top[j] * opacity + bottom[j] * (1.f - opacity); \ } \ - dst += dst_linesize; \ - top += top_linesize; \ - bottom += bottom_linesize; \ + _dst += dst_linesize; \ + _top += top_linesize; \ + _bottom += bottom_linesize; \ } \ }