Description
-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 13.2.0, and the relevant ticket is available at: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114217
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;
}