NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/60393: hash-locked atomic_store_* is all kinds of busted



>Number:         60393
>Category:       kern
>Synopsis:       hash-locked atomic_store_* is all kinds of busted
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Jul 02 14:00:00 +0000 2026
>Originator:     Taylor R Campbell
>Release:        current, 11, 10, 9
>Organization:
.cnI ,egarotS cimotA
>Environment:
>Description:

	Byte-sized atomic_store_* on hash-locked architectures with
	test-and-set but no compare-and-swap (sparc, hppa) work as
	follows:

		uint8_t v;
		unsigned s = 8 * ((uintptr_t)p & 3);
		uint32_t o, n, m = ~(0xffU << s);

		memcpy(&v, q, 1);
		do {
			o = atomic_load_relaxed(p32);
			n = (o & m) | ((uint32_t)v << s);
		} while (atomic_cas_32(p32, o, n) != o);

	This approach is necessary in order for atomic_cas_* to
	cooperate with atomic_cas_* -- if a regular store could happen
	during a concurrent atomic_cas_* on another CPU, it might catch
	the atomic_cas_* in the middle of a hash-locked sequence,
	violating the atomicity.

	But it is broken for two reasons.

	1. It is endian-dependent.  Need

		s = 8 (1 - ((uintptr_t)3 & 3))

	   to work on big-endian.

	2. It cooperates with atomic_cas_* on the same word, but it
	   doesn't cooperate with regular stores _of other bytes_ on
	   the same word.

	The 16-bit path is also broken for a third reason:

		unsigned s = 8 * (((uintptr_t)p & 2) >> 1);

	This either needs to be 16 * (((uintptr_t)p & 2) >> 1), or just
	8 * ((uintptr_t)p & 2).

	(Thanks to yamaguchi@ for figuring out my stupid mistakes!)

>How-To-Repeat:

	cd /usr/tests/net/if_pppoe && atf-run t_pppoe | atf-report

	We should really have direct tests of atomc_load/store_* too.
	Would've saved me some embarrassment.

>Fix:

	Yes, please!




Home | Main Index | Thread Index | Old Index