[FFmpeg-trac] #7226(avfilter:new): Generic vf_blend implementation contains unaligned memory access

FFmpeg trac at avcodec.org
Wed May 23 19:59:52 EEST 2018


#7226: Generic vf_blend implementation contains unaligned memory access
----------------------------------+--------------------------------------
             Reporter:  Lastique  |                     Type:  defect
               Status:  new       |                 Priority:  normal
            Component:  avfilter  |                  Version:  git-master
             Keywords:  vf_blend  |               Blocked By:
             Blocking:            |  Reproduced by developer:  0
Analyzed by developer:  0         |
----------------------------------+--------------------------------------
 Summary of the bug:

 The generic C implementation of the vf_blend filter
 (libavfilter/vf_blend.c, see macros and functions `blend_*_16bit`) for
 16-bit components performs possibly unaligned loads and stores of
 `uint16_t` components. This is done as a result of casting `uint8_t*`
 pointers to `uint16_t*` and then reading and writing data through the
 casted pointers.

 On some architectures unaligned memory access is not permitted.
 Additionally, given the casts the compiler is free to falsely assume the
 pointers are aligned and apply optimizations that are not valid if the
 pointers are not aligned.

 In my case, I'm building ffmpeg from sources with gcc 7.3.0 and
 vectorization enabled (I modified `configure` script to not disable
 vectorization) for x86-64. The compiler vectorizes the loops in the
 `blend_*_16bit` functions and performs aligned loads of the input data.
 However, the `checkasm --test=vf_blend` then crashes as it passes
 unaligned pointers to the blend algorithm implementation. Here is the
 backtrace:

 {{{
 Program received signal SIGSEGV, Segmentation fault.
 0x0000555555736130 in blend_addition_16bit (_top=<optimized out>,
 top_linesize=<optimized out>, _bottom=<optimized out>,
 bottom_linesize=<optimized out>, _dst=<optimized out>,
 dst_linesize=<optimized out>, width=128, height=256, param=0x7fffffffd130,
 values=0x0, starty=-134463424)
     at src/libavfilter/vf_blend.c:281
 281     src/libavfilter/vf_blend.c: No such file or directory.
 (gdb) bt
 #0  0x0000555555736130 in blend_addition_16bit (_top=<optimized out>,
 top_linesize=<optimized out>, _bottom=<optimized out>,
 bottom_linesize=<optimized out>, _dst=<optimized out>,
 dst_linesize=<optimized out>, width=128, height=256, param=0x7fffffffd130,
 values=0x0, starty=-134463424)
     at src/libavfilter/vf_blend.c:281
 #1  0x00005555557057a6 in checkasm_check_blend () at
 src/tests/checkasm/vf_blend.c:126
 #2  0x00005555556ebc39 in check_cpu_flag (flag=<optimized out>, name=0x0)
 at src/tests/checkasm/checkasm.c:572
 #3  0x00005555556ebc39 in main (argc=<optimized out>, argv=<optimized
 out>) at src/tests/checkasm/checkasm.c:680
 }}}

 The fault instruction is `movdqa (%r12,%rax,1),%xmm0` which attempts to
 load aligned 16 bytes from effective address 0x7ffff7fd4041. The compiler
 also generated pre-alignment code, which assumes that the initial pointer
 is aligned to 2 bytes boundary, which is why the compiler used the aligned
 load.

 I understand that the unmodified ffmpeg on x86 is likely not affected
 because x86 allows unaligned 16-bit loads and stores and vectorization is
 disabled by default. However, I still think the code in question is not
 correct and can fail on other architectures.

 How to reproduce:

 1. Compile ffmpeg with vectorization enabled. For that comment the
 `check_optflags -fno-tree-vectorize` line in `configure` (I'm attaching
 the actual patch I used). I don't believe the actual `configure` flags are
 important but here is what I used:

 {{{
 ./configure --prefix=/usr --extra-version="1mind1" --toolchain=hardened
 --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu
 --enable-gpl --disable-stripping --enable-avresample --disable-
 filter=resample --enable-avisynth --enable-ladspa --enable-libass
 --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio
 --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-
 libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-
 libjack --enable-libmp3lame --enable-libopenjpeg --enable-libopenmpt
 --enable-libopus --enable-libpulse --enable-librsvg --enable-librubberband
 --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex
 --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvorbis
 --enable-libvpx --enable-libaom --enable-libwavpack --enable-libwebp
 --enable-libopenh264 --enable-libx265 --enable-libxml2 --enable-libxvid
 --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal
 --enable-opengl --enable-sdl2 --enable-libmysofa --enable-libdc1394
 --enable-libdrm --enable-libiec61883 --disable-chromaprint --enable-frei0r
 --enable-libopencv --enable-libx264 --enable-shared --enable-gnutls
 }}}

 The compiler used: gcc 7.3.0 on Kubuntu 18.04. Compile for x86-64.

 2. Run the vf_blend test: `tests/checkasm/checkasm --test=vf_blend`. The
 test will crash.

 I found this problem with ffmpeg 4.0, but the current git master seems to
 have the same code in libavfilter/vf_blend.c, so I assume it is affected
 as well.

--
Ticket URL: <https://trac.ffmpeg.org/ticket/7226>
FFmpeg <https://ffmpeg.org>
FFmpeg issue tracker


More information about the FFmpeg-trac mailing list