avcodec/startcode: Avoid unaligned accesses

Up until now, ff_startcode_find_candidate_c() simply casts
an uint8_t* to uint64_t*/uint32_t* to read 64/32 bits at a time
in case HAVE_FAST_UNALIGNED is true. Yet this ignores the
alignment requirement of these types as well as effective type
rules of the C standard. This commit therefore replaces these
direct accesses with AV_RN64/32; this also improves
readability.

UBSan reported these unaligned accesses which happened in 233
FATE-tests involving H.264 and VC-1 (this has also been reported
in tickets #8138 and #8485); these tests are fixed by this commit.

The output of GCC with -O3 is unchanged for aarch64, loongarch,
ppc and x64 (as well as for arches like alpha for which
HAVE_FAST_UNALIGNED is never true in the first place).
There was only a slight difference for mips and arm.
I don't know about the speed impact of them.

Reviewed-by: Anton Khirnov <anton@khirnov.net>
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
This commit is contained in:
Andreas Rheinhardt 2020-01-22 00:55:22 +01:00
parent b9058765d7
commit 30e1f5ec77
1 changed files with 5 additions and 4 deletions

View File

@ -25,6 +25,7 @@
* @author Michael Niedermayer <michaelni@gmx.at>
*/
#include "libavutil/intreadwrite.h"
#include "startcode.h"
#include "config.h"
@ -38,14 +39,14 @@ int ff_startcode_find_candidate_c(const uint8_t *buf, int size)
*/
#if HAVE_FAST_64BIT
while (i < size &&
!((~*(const uint64_t *)(buf + i) &
(*(const uint64_t *)(buf + i) - 0x0101010101010101ULL)) &
!((~AV_RN64(buf + i) &
(AV_RN64(buf + i) - 0x0101010101010101ULL)) &
0x8080808080808080ULL))
i += 8;
#else
while (i < size &&
!((~*(const uint32_t *)(buf + i) &
(*(const uint32_t *)(buf + i) - 0x01010101U)) &
!((~AV_RN32(buf + i) &
(AV_RN32(buf + i) - 0x01010101U)) &
0x80808080U))
i += 4;
#endif