swab: Correctly treat the data as misaligned

The __aligned attribute in the previous version applied to the location
of the pointers, not the data the pointers pointed to.  While this
could be fixed by applying the attribute to a local typedef of uint16_t,
just using memcpy() for the unaligned access is simpler and ISO C.

This fixes the build on CHERI architectures which do not support
misaligned pointers and were thus failing with:

lib/libc/string/swab.c:12:18: error: alignment (1) of 'const uint16_t *' (aka 'const unsigned short *') is less than the required capability alignment (16) [-Werror,-Wcheri-capability-misuse]
   12 |         const uint16_t *f __aligned(1) = from;
      |

Co-authored by:	Jessica Clarke <jrtc27@FreeBSD.org>
Fixes:		02ebbc781f ("swab: Fix implementation to support overlapping copies")
Sponsored by:	AFRL, DARPA

Reviewed by:	markj
Differential Revision:	https://reviews.freebsd.org/D54399
This commit is contained in:
John Baldwin
2026-01-14 12:10:33 -05:00
parent fef84fd8ae
commit 2a5c5b8f7c
+10 -3
View File
@@ -3,14 +3,16 @@
* Copyright (c) 2024 rilysh <nightquick@proton.me>
*/
#include <string.h>
#include <unistd.h>
#include <sys/endian.h>
void
swab(const void * __restrict from, void * __restrict to, ssize_t len)
{
const uint16_t *f __aligned(1) = from;
uint16_t *t __aligned(1) = to;
const char *f = from;
char *t = to;
uint16_t tmp;
/*
* POSIX says overlapping copy behavior is undefined, however many
@@ -19,7 +21,12 @@ swab(const void * __restrict from, void * __restrict to, ssize_t len)
* and swapping them before writing them back accomplishes this.
*/
while (len > 1) {
*t++ = bswap16(*f++);
memcpy(&tmp, f, 2);
tmp = bswap16(tmp);
memcpy(t, &tmp, 2);
f += 2;
t += 2;
len -= 2;
}
}