NetBSD Problem Report #59126

From www@netbsd.org  Tue Mar  4 00:18:32 2025
Return-Path: <www@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
	 key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256
	 client-signature RSA-PSS (2048 bits) client-digest SHA256)
	(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
	by mollari.NetBSD.org (Postfix) with ESMTPS id D74781A923A
	for <gnats-bugs@gnats.NetBSD.org>; Tue,  4 Mar 2025 00:18:32 +0000 (UTC)
Message-Id: <20250304001831.6161F1A923D@mollari.NetBSD.org>
Date: Tue,  4 Mar 2025 00:18:31 +0000 (UTC)
From: campbell+netbsd@mumble.net
Reply-To: campbell+netbsd@mumble.net
To: gnats-bugs@NetBSD.org
Subject: pthread_once(3): missing memory ordering
X-Send-Pr-Version: www-1.0

>Number:         59126
>Category:       lib
>Synopsis:       pthread_once(3): missing memory ordering
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    riastradh
>State:          needs-pullups
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Mar 04 00:20:00 +0000 2025
>Closed-Date:    
>Last-Modified:  Tue Mar 04 02:25:05 +0000 2025
>Originator:     Taylor R Campbell
>Release:        current, 10, 9, ...
>Organization:
The NetBSD Oncelerbarrier
>Environment:
>Description:
The critical rule of pthread_once(O, I) is that any memory operations during I() in any thread happen-before all memory operations after pthread_once returns.

But the optimistic unlocked test in pthread_once does not guarantee this.  It needs membar_release/acquire at least.
>How-To-Repeat:
The following test program probably exhibits the issue on multicore machines with relaxed memory ordering (link with -pthread, run with the number of parallel threads to try, hit ^T for progress or ^C if you get tired of waiting):

#include <err.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

unsigned long long nloop;

static void
onsig(int signo)
{
	char buf[128];

	snprintf_ss(buf, sizeof(buf), "signal %d after %llu trials\n", signo,
	    nloop);
	(void)write(STDOUT_FILENO, buf, strlen(buf));
	if (signo == SIGINFO)
		return;
	(void)signal(signo, SIG_DFL);
	(void)raise(signo);
}

pthread_once_t once, once0 = PTHREAD_ONCE_INIT;
int done = 0;

static void
init(void)
{

	done = 1;
}

static void *
thread(void *cookie)
{
	pthread_barrier_t *bar = cookie;

	(void)pthread_barrier_wait(bar);
	pthread_once(&once, &init);
	if (!done)
		errx(1, "fail after %llu trials", nloop);
}

int
main(int argc, char **argv)
{
	enum { N = 256 };
	unsigned n = argc == 2 ? atoi(argv[1]) : 16;

	if (n < 1)
		errx(1, "not enough");
	if (n > N)
		errx(1, "too many");

	if (signal(SIGINT, &onsig) == SIG_ERR)
		err(1, "signal(SIGINT)");
	if (signal(SIGINFO, &onsig) == SIG_ERR)
		err(1, "signal(SIGINFO)");

	for (;; nloop++) {
		pthread_barrier_t bar;
		pthread_t t[N];
		unsigned i;
		int error;

		error = pthread_barrier_init(&bar, NULL, n);
		if (error)
			errc(1, error, "pthread_barrier_init");
		for (i = 0; i < n - 1; i++) {
			error = pthread_create(&t[i], NULL, &thread, &bar);
			if (error)
				errc(1, error, "pthread_create");
		}
		once = once0;
		done = 0;
		(void)pthread_barrier_wait(&bar);
		pthread_once(&once, &init);
		if (!done)
			errx(1, "fail");
		for (i = 0; i < n - 1; i++) {
			error = pthread_join(t[i], NULL);
			if (error)
				errc(1, error, "pthread_join");
		}
		error = pthread_barrier_destroy(&bar);
		if (error)
			errc(1, error, "pthread_barrier_destroy");
	}
}

>Fix:
membar_release/acquire

>Release-Note:

>Audit-Trail:
From: "Taylor R Campbell" <riastradh@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/59126 CVS commit: src/common/lib/libc/atomic
Date: Tue, 4 Mar 2025 00:40:42 +0000

 Module Name:	src
 Committed By:	riastradh
 Date:		Tue Mar  4 00:40:42 UTC 2025

 Modified Files:
 	src/common/lib/libc/atomic: atomic_op_namespace.h

 Log Message:
 libc atomic_op_namespace.h: Add membar_release and membar_acquire.

 These namespace macros will be needed so that libpthread can call
 NetBSD's nonstandard membar_release/acquire functions even if linked
 against an application that defines symbols of the same name.

 Preparation for:

 PR lib/59126: pthread_once(3): missing memory ordering


 To generate a diff of this commit:
 cvs rdiff -u -r1.7 -r1.8 src/common/lib/libc/atomic/atomic_op_namespace.h

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: "Taylor R Campbell" <riastradh@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/59126 CVS commit: src/lib/libpthread
Date: Tue, 4 Mar 2025 00:41:00 +0000

 Module Name:	src
 Committed By:	riastradh
 Date:		Tue Mar  4 00:41:00 UTC 2025

 Modified Files:
 	src/lib/libpthread: pthread_once.c

 Log Message:
 pthread_once(3): Add missing memory barriers.

 PR lib/59126: pthread_once(3): missing memory ordering


 To generate a diff of this commit:
 cvs rdiff -u -r1.4 -r1.5 src/lib/libpthread/pthread_once.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

Responsible-Changed-From-To: lib-bug-people->riastradh
Responsible-Changed-By: riastradh@NetBSD.org
Responsible-Changed-When: Tue, 04 Mar 2025 02:25:05 +0000
Responsible-Changed-Why:
fixed in HEAD, needs pullup-9 and pullup-10
(confirmed reproducer fails on 4x arm cortex-a53 too)


State-Changed-From-To: open->needs-pullups
State-Changed-By: riastradh@NetBSD.org
State-Changed-When: Tue, 04 Mar 2025 02:25:05 +0000
State-Changed-Why:
mine


>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.47 2022/09/11 19:34:41 kim Exp $
$NetBSD: gnats_config.sh,v 1.9 2014/08/02 14:16:04 spz Exp $
Copyright © 1994-2025 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.