https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114217
Bug ID: 114217
Summary: -fsanitize=alignment false positive with intended
unaligned struct member access
Product: gcc
Version: 13.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: sanitizer
Assignee: unassigned at gcc dot gnu.org
Reporter: akihiko.odaki at daynix dot com
CC: dodji at gcc dot gnu.org, dvyukov at gcc dot gnu.org,
jakub at gcc dot gnu.org, kcc at gcc dot gnu.org
Target Milestone: ---
-fsanitize=alignment generates a false positive error for an intended unaligned
struct member access. The intention of unaligned struct member access is
expressed with __builtin_memcpy() as done by QEMU or packed struct access as
done by Linux. GCC translates such a construct to code to access memory
unaligned for architectures like rv64gc as intended but also emits code to
enforce the alignment.
The relevant code of QEMU is at:
https://gitlab.com/qemu-project/qemu/-/blob/v8.2.1/include/qemu/bswap.h?ref_type=tags
The relevant code of Linux is at:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/asm-generic/unaligned.h?h=v6.7
FYI, this issue is reproducible also with clang 17.0.1, and I'm going to open
an issue for it, too.
To reproduce the issue, compile the code shown below with -O2
-fsanitize=alignment for rv64gc:
#include <stdint.h>
typedef uint64_t u64;
/*
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/compiler_attributes.h?h=v6.7
*/
/*
* gcc:
https://gcc.gnu.org/onlinedocs/gcc/Common-Type-Attributes.html#index-packed-type-attribute
* clang:
https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-packed-variable-attribute
*/
#define __packed __attribute__((__packed__))
/*
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/asm-generic/unaligned.h?h=v6.7
*/
#define __get_unaligned_t(type, ptr) ({
\
const struct { type x; } __packed *__pptr = (typeof(__pptr))(ptr);
\
__pptr->x;
\
})
#define __put_unaligned_t(type, val, ptr) do {
\
struct { type x; } __packed *__pptr = (typeof(__pptr))(ptr);
\
__pptr->x = (val);
\
} while (0)
#define get_unaligned(ptr) __get_unaligned_t(typeof(*(ptr)), (ptr))
#define put_unaligned(val, ptr) __put_unaligned_t(typeof(*(ptr)), (val), (ptr))
/*
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/btrfs/inode.c?h=v6.7
*/
struct dir_entry {
u64 ino;
u64 offset;
unsigned type;
int name_len;
};
/*
* This function is intended to perform an unaligned access.
* GCC emits code for an unaligned operation as intended,
* but also emits code to assert alignment.
*/
u64 f(struct dir_entry *entry)
{
return get_unaligned(&entry->offset);
}
/*
* This function is intended to perform an aligned access.
* GCC emits code for an aligned operation,
* and emits code to assert alignment.
*/
u64 g(struct dir_entry *entry)
{
return entry->offset;
}