Page MenuHomeFreeBSD

swab: Correctly treat the data as misaligned
ClosedPublic

Authored by jhb on Mon, Dec 29, 5:24 PM.
Tags
None
Referenced Files
F142184340: D54399.id.diff
Fri, Jan 16, 11:03 PM
F142133565: D54399.id168718.diff
Fri, Jan 16, 8:38 AM
Unknown Object (File)
Thu, Jan 15, 5:39 PM
Unknown Object (File)
Wed, Jan 14, 6:39 AM
Unknown Object (File)
Sat, Jan 10, 4:50 AM
Unknown Object (File)
Thu, Jan 8, 11:18 AM
Unknown Object (File)
Thu, Jan 8, 5:53 AM
Unknown Object (File)
Mon, Jan 5, 12:27 PM
Subscribers
None

Details

Summary

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: 02ebbc781f08 ("swab: Fix implementation to support overlapping copies")
Sponsored by: AFRL, DARPA

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped
Build Status
Buildable 69546
Build 66429: arc lint + arc unit

Event Timeline

jhb requested review of this revision.Mon, Dec 29, 5:24 PM
jhb created this revision.

I tried various permutations of alignas and that didn't work either. Also, alignas apparently can't weaken alignment, only strengthen it, and alignas can't be used in a typedef.

I also wonder if this is really doing what is wanted anyway. Presumably armv7 is an architecture where this should be using an unaligned load (or individual byte loads)?

Hmm, looking at the code both before and after this change on armv7, it is just using plain ldrh and strh which will fault on unaligned accesses?

(gdb) disassemble swab 
Dump of assembler code for function swab:
   0x00000000 <+0>:     cmp     r2, #2
   0x00000004 <+4>:     bxlt    lr
   0x00000008 <+8>:     add     r2, r2, #2
   0x0000000c <+12>:    ldrh    r3, [r0], #2
   0x00000010 <+16>:    sub     r2, r2, #2
   0x00000014 <+20>:    cmp     r2, #3
   0x00000018 <+24>:    rev     r3, r3
   0x0000001c <+28>:    lsr     r3, r3, #16
   0x00000020 <+32>:    strh    r3, [r1], #2
   0x00000024 <+36>:    bhi     0xc <swab+12>
   0x00000028 <+40>:    bx      lr
End of assembler dump.

Personally I would avoid confusing GNU C underaligned attributes and just write it in ISO C using memcpy. LLVM will inline the memcpy as load(s) based on the target's unaligned access support anyway. That is:

	const char *f = from;
	char *t = to;
	uint16_t tmp;

	/*
	 * POSIX says overlapping copy behavior is undefined, however many
	 * applications assume the old FreeBSD and current GNU libc behavior
	 * that will swap the bytes correctly when from == to. Reading both bytes
	 * and swapping them before writing them back accomplishes this.
	 */
	while (len > 1) {
		memcpy(&tmp, f, 2);
		tmp = bswap16(tmp);
		memcpy(t, &tmp, 2);

		f += 2;
		t += 2;
		len -= 2;
	}

Ideally we'd just write the unsigned char tmp; tmp = f[0]; t[1] = f[0]; t[0] = tmp; version but for some reason that doesn't get vectorised, only unrolled.

Also I'm pretty sure that 02ebbc781f082df9714e74775700d8c08bac7850 should have dropped the __restrict, given we're now supporting from == to and modifying using the former whilst reading with the latter, but it's possible that's valid if the pointers are identical (definitely not if overlapping but not identical).

In D54399#1243356, @jhb wrote:

Hmm, looking at the code both before and after this change on armv7, it is just using plain ldrh and strh which will fault on unaligned accesses?

Armv6 added SCTLR.U (CPU_CONTROL_UNAL_ENABLE in FreeBSD, because sys/arm doesn't use Arm's nomenclature...) to allow unaligned accesses. It's v5 and below that's dodgy, and this change post-dates that removal.

Yes, I like the memcpy version better.

The arm assembly for the memcpy() variant is identical FWIW.

jhb retitled this revision from swab: Correctly annotate the data as misaligned. to swab: Correctly treat the data as misaligned.Wed, Dec 31, 12:52 PM
jhb edited the summary of this revision. (Show Details)
jhb edited the summary of this revision. (Show Details)
This revision is now accepted and ready to land.Wed, Jan 14, 1:46 PM
This revision was automatically updated to reflect the committed changes.