NetBSD Problem Report #60101

From www@netbsd.org  Thu Mar 19 01:40:50 2026
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 "R12" (not verified))
	by mollari.NetBSD.org (Postfix) with ESMTPS id 403AD1A9239
	for <gnats-bugs@gnats.NetBSD.org>; Thu, 19 Mar 2026 01:40:50 +0000 (UTC)
Message-Id: <20260319014049.214E11A923A@mollari.NetBSD.org>
Date: Thu, 19 Mar 2026 01:40:49 +0000 (UTC)
From: pyhirricturtle@gmail.com
Reply-To: pyhirricturtle@gmail.com
To: gnats-bugs@NetBSD.org
Subject: vax: __lwp_getprivate_fast() inline asm uses GCC-specific register variable pattern, not portable
X-Send-Pr-Version: www-1.0
X-From4GNATS: "pyhirricturtle@gmail.com via gnats" <gnats-admin@NetBSD.org>

>Number:         60101
>Category:       port-vax
>Synopsis:       vax: __lwp_getprivate_fast() inline asm uses GCC-specific register variable pattern, not portable
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    port-vax-maintainer
>State:          closed
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Mar 19 01:45:00 +0000 2026
>Closed-Date:    Tue Jun 30 13:38:32 +0000 2026
>Last-Modified:  Tue Jun 30 13:38:32 +0000 2026
>Originator:     FireTurtle
>Release:        NetBSD 10.1_STABLE
>Organization:
>Environment:
VAX (any), sys/arch/vax/include/mcontext.h
>Description:
The __lwp_getprivate_fast() function in sys/arch/vax/include/mcontext.h uses a GCC-specific inline asm pattern to read the syscall return value from r0:

    register void *tcb __asm("r0");
    __asm("chmk %0" :: "i"(SYS__lwp_getprivate) : "r0");
    return tcb;

This relies on GCC-specific behavior where register variables bound to a specific register survive that register being listed as a clobber. The C standard and the GCC documentation for clobbers do not guarantee this — clobbering r0 tells the compiler that r0 is destroyed by the asm statement.

Compilers that implement clobbers strictly (such as Clang) treat r0 as destroyed after the asm, making the subsequent read of tcb undefined. At optimization levels above -O0, the compiler may eliminate code that depends on the return value, since the value is provably undefined.

Because __lwp_getprivate_fast() is inlined into pthread__self() (pthread_int.h), which is called from pthread_mutex_lock() and many other libpthread functions, this can cause those functions to be miscompiled — the optimizer removes the function body after the chmk, leaving no ret instruction. Execution falls through into the next function in the text segment, hitting a HALT (opcode 0x00 from the .word entry mask) and causing SIGILL.

Symptoms: any program linked against libpthread.so crashes with SIGILL during library initialization (before main() is reached), if libpthread was compiled with a non-GCC compiler at -O1 or higher.
>How-To-Repeat:
Compile libpthread (or any code that includes <machine/mcontext.h> and calls __lwp_getprivate_fast()) with a compiler other than GCC, such as Clang, at -O1 or higher. The compiled code will be missing instructions after the chmk syscall.

To see the issue directly, compile a file containing:

    #include <sys/syscall.h>
    static inline void *test(void) {
        register void *tcb __asm("r0");
        __asm("chmk %0" :: "i"(316) : "r0");
        return tcb;
    }
    int use(void) {
        void *p = test();
        if (p == (void *)0) return 1;
        return 0;
    }

With GCC, the comparison against NULL is preserved. With Clang (or any compiler that treats clobbers strictly), the comparison is optimized away because tcb has no defined value after r0 is clobbered.
>Fix:
Change the inline asm to use a proper output constraint instead of the clobber pattern:

--- a/sys/arch/vax/include/mcontext.h
+++ b/sys/arch/vax/include/mcontext.h
@@ -86,7 +86,7 @@
 __lwp_getprivate_fast(void)
 {
 register void *tcb __asm("r0");
-__asm("chmk %0" :: "i"(SYS__lwp_getprivate) : "r0");
+__asm volatile("chmk %1" : "=r"(tcb) : "i"(SYS__lwp_getprivate));
 return tcb;
 }

The =r output constraint tells the compiler that tcb receives a value from the asm statement. Combined with register ... __asm("r0"), this forces r0 as the output register. The volatile qualifier prevents the asm from being optimized away or reordered. This is compatible with both GCC and Clang.

>Release-Note:

>Audit-Trail:

State-Changed-From-To: open->needs-pullups
State-Changed-By: riastradh@NetBSD.org
State-Changed-When: Thu, 19 Mar 2026 04:39:43 +0000
State-Changed-Why:
fixed in HEAD, needs pullup-11, pullup-10, pullup-9
(note: code moved to lwp_private.h from lwp.h after 9 and 10)


From: "Taylor R Campbell" <riastradh@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/60101 CVS commit: src/sys/arch/vax/include
Date: Thu, 19 Mar 2026 04:38:07 +0000

 Module Name:	src
 Committed By:	riastradh
 Date:		Thu Mar 19 04:38:07 UTC 2026

 Modified Files:
 	src/sys/arch/vax/include: lwp_private.h

 Log Message:
 vax __lwp_getprivate_fast: Fix asm constraints.

 r0 is not clobbered; it is the output.  So say so.

 No volatile is needed here, and volatile would be wrong, because
 calls to __lwp_getprivate_fast can be safely deleted if the result is
 not used.

 PR port-vax/60101: vax: __lwp_getprivate_fast() inline asm uses
 GCC-specific register variable pattern, not portable


 To generate a diff of this commit:
 cvs rdiff -u -r1.1 -r1.2 src/sys/arch/vax/include/lwp_private.h

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

State-Changed-From-To: needs-pullups->pending-pullups
State-Changed-By: riastradh@NetBSD.org
State-Changed-When: Mon, 29 Jun 2026 19:53:08 +0000
State-Changed-Why:
pullup-11 #353 https://releng.netbsd.org/cgi-bin/req-11.cgi?show=353
pullup-10 #1297 https://releng.netbsd.org/cgi-bin/req-10.cgi?show=1297
pullup-9 #2027 https://releng.netbsd.org/cgi-bin/req-9.cgi?show=2027


From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/60101 CVS commit: [netbsd-11] src/sys/arch/vax/include
Date: Tue, 30 Jun 2026 09:30:34 +0000

 Module Name:	src
 Committed By:	martin
 Date:		Tue Jun 30 09:30:34 UTC 2026

 Modified Files:
 	src/sys/arch/vax/include [netbsd-11]: lwp_private.h

 Log Message:
 Pull up following revision(s) (requested by riastradh in ticket #353):

 	sys/arch/vax/include/lwp_private.h: revision 1.2

 vax __lwp_getprivate_fast: Fix asm constraints.
 r0 is not clobbered; it is the output.  So say so.

 No volatile is needed here, and volatile would be wrong, because
 calls to __lwp_getprivate_fast can be safely deleted if the result is
 not used.

 PR port-vax/60101: vax: __lwp_getprivate_fast() inline asm uses
 GCC-specific register variable pattern, not portable


 To generate a diff of this commit:
 cvs rdiff -u -r1.1 -r1.1.2.1 src/sys/arch/vax/include/lwp_private.h

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

From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/60101 CVS commit: [netbsd-10] src/sys/arch/vax/include
Date: Tue, 30 Jun 2026 09:34:55 +0000

 Module Name:	src
 Committed By:	martin
 Date:		Tue Jun 30 09:34:55 UTC 2026

 Modified Files:
 	src/sys/arch/vax/include [netbsd-10]: mcontext.h

 Log Message:
 Pull up following revision(s) (requested by riastradh in ticket #1297):

 	sys/arch/vax/include/mcontext.h (patch)
 		from: sys/arch/vax/include/lwp_private.h: revision 1.2

 vax __lwp_getprivate_fast: Fix asm constraints.
 r0 is not clobbered; it is the output.  So say so.

 No volatile is needed here, and volatile would be wrong, because
 calls to __lwp_getprivate_fast can be safely deleted if the result is
 not used.

 PR port-vax/60101: vax: __lwp_getprivate_fast() inline asm uses
 GCC-specific register variable pattern, not portable


 To generate a diff of this commit:
 cvs rdiff -u -r1.10.26.1 -r1.10.26.2 src/sys/arch/vax/include/mcontext.h

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

From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/60101 CVS commit: [netbsd-9] src/sys/arch/vax/include
Date: Tue, 30 Jun 2026 09:37:12 +0000

 Module Name:	src
 Committed By:	martin
 Date:		Tue Jun 30 09:37:11 UTC 2026

 Modified Files:
 	src/sys/arch/vax/include [netbsd-9]: mcontext.h

 Log Message:
 Pull up following revision(s) (requested by riastradh in ticket #2027):

 	sys/arch/vax/include/mcontext.h (patch)
 		from: sys/arch/vax/include/lwp_private.h: revision 1.2

 vax __lwp_getprivate_fast: Fix asm constraints.
 r0 is not clobbered; it is the output.  So say so.

 No volatile is needed here, and volatile would be wrong, because
 calls to __lwp_getprivate_fast can be safely deleted if the result is
 not used.

 PR port-vax/60101: vax: __lwp_getprivate_fast() inline asm uses
 GCC-specific register variable pattern, not portable


 To generate a diff of this commit:
 cvs rdiff -u -r1.9 -r1.9.8.1 src/sys/arch/vax/include/mcontext.h

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

State-Changed-From-To: pending-pullups->closed
State-Changed-By: riastradh@NetBSD.org
State-Changed-When: Tue, 30 Jun 2026 13:38:32 +0000
State-Changed-Why:
fixed in HEAD, pulled up to 11, 10, and 9


>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.51 2026/08/10 02:28:17 riastradh Exp $
$NetBSD: gnats_config.sh,v 1.10 2026/05/13 22:00:09 riastradh Exp $
Copyright © 1994-2026 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.