From patchwork Tue Sep 29 02:02:50 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?5b6M6JekIOmBvCjmlrDoo73lk4HplovnmbozKQ==?= X-Patchwork-Id: 144821 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 0D0964BA540B for ; Tue, 29 Sep 2026 02:07:44 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0D0964BA540B Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=aiphone.co.jp header.i=@aiphone.co.jp header.a=rsa-sha256 header.s=mg header.b=i/WKxj8A X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mgspc02.cybermail.jp (mgspc02.cybermail.jp [27.121.5.177]) by sourceware.org (Postfix) with ESMTPS id 8B66E4BA798D for ; Tue, 29 Sep 2026 02:07:08 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8B66E4BA798D Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=aiphone.co.jp Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=aiphone.co.jp ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 8B66E4BA798D Authentication-Results: sourceware.org; arc=none smtp.remote-ip=27.121.5.177 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1790647629; cv=none; b=xe3Z3Ex9mLFpFyJF/0DfoYZmWblzR9lZEt5Ex7sRy1ouFTds2WjDjweQUbL6iW944wdY/DSXL3jVgQW9yOLzP1VCeXqvuV4GwhDoQH61NhMf0+nup1d8VnA1oQAaWWkzbGC2MMaqGv6vM5rcIqiJQfGztIye6C4mtuQBSgk7Mtc= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1790647629; c=relaxed/simple; bh=yy7H7OwCiCwBHwVMtks7DRv+xoqH7L0qlb6rhY/EZlM=; h=DKIM-Signature:Date:Subject:From:To:Message-ID:mime-version; b=c6D5cVdkg7YDpfbrMErWMW65i6MnRxr46SIBSmSvyDKScEMDy5Uv2ePoQSnUgDCyIoh5TTMyPTVfv0Lsrp4jDfVcwBtNE17uUmudMtAh43DJ7krHVK0McJYSww0NlfiF7m0asFGc3CzZLFcGpmtvQbtMZojda6/BdK2VsIBUVe0= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=aiphone.co.jp header.i=@aiphone.co.jp header.a=rsa-sha256 header.s=mg header.b=i/WKxj8A DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8B66E4BA798D X-MailGates: (SIP:2,PASS,NONE)(RELAYCHK:2,PASS)(audit_rules:ggAAAAAAAAAF CUIJVStdYRk1IxpKNzkjWQFWVQJWe08Vbn0cAC1MVFopUlldHVAiSS4MJTRcSxskeW8fAQhC DycURnAnXUooURlzJhgGWBNXKwAsF24tAxJENxJofCk3dzUXO3cKdn4tDGpJdgkyCnQzbgBi ADkEGD1xPB8QdAFMJx1NZE4PMTE7)(compute_score:DELIVER,40,3) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=aiphone.co.jp; s=mg; t=1790647625; bh=axWu+tNxU8H1vwIXQAo3ZmCadk09JQTe292SqdXSthU=; h=Date:From:To:Cc; b=i/WKxj8Aic6wG8PUiyc1KDJHxoW+Pr8Q69lk5vKDmnpfxpKHBbuUMgeofZn3ws4cB +aPjAOvXfuzyV3IHYoJ9JXsoiWxKH6KAvVE6AR7cJI/MiocofOS1ivX04gvOWtRkbz ZT/Ji/N8FP9BGM082L094okdE0FhiP9BvGPNCRJUdKuO1QNulyLd4yb6mFqNnkwEBb BvodzvjTmJHmfqyuagX8070sW6UCb0fx3SzWDu7H48Sb/sbcyz/6qcThntcS2AfpJC Sm0fOCDdWqMCjE9usVayzw/KK8MzKtrKbDWWBHXZWIaNuZz0IjYyr8ST8oA5Zf6GsN B8ohv3ZpITqZg== X-MGADT: RgAAAAAAAAAFEUIJVStdYRk1IxpKNzkjWQFWVQJWe08Vbn0cAC1MVFopUlldHVAiSS4MJ TRcSxskeW8fAQhCDycURnAnXUooURl1aFs3 Received: from 172.23.2.1 by mgspc02.cybermail.jp with (882053:1:AUTH_RELAY) (envelope-from ); Tue, 29 Sep 2026 11:02:51 +0900 (JST) X-M2K-DINF: v=1; em=2; eh=9903a364/Y0oDcB; ec=99c04cbc; m=icXr1KjiyWwu4wwvPLauxp4D 0BuvQR0CrAgY0ZCrEP1f4E9qCdigE01LA9E8cq9dSG8yoRCvxQZXThdebeFQYDLiYMYaVXyrWznq fIES4a0oYzApZ9ubwYQ5AP++IqLkolvDKwcRHEpja2s3KGAnzA== Received: from 103.79.14.187 by cmspc08-2.cybermail.jp with Mail2000 ESMTPSA Server V8.00(394896:0:AUTH_LOGIN) (envelope-from ) (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128 group=x25519); Tue, 29 Sep 2026 11:02:50 +0900 (JST) Date: Tue, 29 Sep 2026 11:02:50 +0900 Subject: [PATCH v2] nptl: Release robust mutex after trylock returns ENOTRECOVERABLE (BZ #27458) From: =?iso-2022-jp?b?IhskQjhlRiMhIU5LGyhCKBskQj83QD1JSjMrSC8bKEIzKSI=?= To: libc-alpha@sourceware.org Cc: adhemerval.zanella@linaro.org X-Mailer: Cybozu(R) Garoon(R) Message-ID: mime-version: 1.0 X-Spam-Status: No, score=-9.4 required=5.0 tests=BAYES_00, CHARSET_FARAWAY_HEADER, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_LOW, SPF_HELO_PASS, SPF_PASS, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org pthread_mutex_trylock on a not-recoverable robust non-PI mutex acquires the lock word using a compare-and-exchange, then returns ENOTRECOVERABLE without releasing it. The CAS returns the old lock word value, which is zero on success, so testing oldval against the thread ID never unlocks the mutex. A subsequent trylock returns EBUSY, and a lock attempt can block indefinitely. Release the lock when oldval is zero. Add a regression test covering normal, recursive, and error-checking robust mutexes with both process-private and process-shared attributes, with and without PI. Skip PI combinations on systems that do not support PI robust mutexes. Tested on x86_64-linux-gnu (WSL2): nptl/tst-robust-trylock-notrecoverable (12 combinations, PASS). Signed-off-by: Ryo Goto --- Copyright status: no FSF assignment; contributing under DCO. Changes since v1: - Rebased the test registration after tst-robust12. - Skip PI cases when pthread_mutex_init returns ENOTSUP. - Cover recursive and error-checking robust mutexes as well. nptl/Makefile | 1 + nptl/pthread_mutex_trylock.c | 2 +- nptl/tst-robust-trylock-notrecoverable.c | 108 ++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 nptl/tst-robust-trylock-notrecoverable.c diff --git a/nptl/Makefile b/nptl/Makefile index dfdfd261..9a8ec659 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -329,6 +329,7 @@ tests = \ tst-pthread_gettid_np \ tst-robust-fork \ tst-robust12 \ + tst-robust-trylock-notrecoverable \ tst-robustpi1 \ tst-robustpi2 \ tst-robustpi3 \ diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c index 15786fda..e1662d00 100644 --- a/nptl/pthread_mutex_trylock.c +++ b/nptl/pthread_mutex_trylock.c @@ -170,7 +170,7 @@ ___pthread_mutex_trylock (pthread_mutex_t *mutex) { /* This mutex is now not recoverable. */ mutex->__data.__count = 0; - if (oldval == id) + if (oldval == 0) lll_unlock (mutex->__data.__lock, PTHREAD_ROBUST_MUTEX_PSHARED (mutex)); /* FIXME This violates the mutex destruction requirements. See diff --git a/nptl/tst-robust-trylock-notrecoverable.c b/nptl/tst-robust-trylock-notrecoverable.c new file mode 100644 index 00000000..f732f42a --- /dev/null +++ b/nptl/tst-robust-trylock-notrecoverable.c @@ -0,0 +1,108 @@ +/* Test that pthread_mutex_trylock releases an unrecoverable robust mutex. + Copyright The GNU Toolchain Authors. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static pthread_mutex_t mutex; + +static void * +lock_and_exit (void *arg) +{ + (void) arg; + TEST_COMPARE (pthread_mutex_lock (&mutex), 0); + return NULL; +} + +static void * +trylock_in_thread (void *arg) +{ + int *result = arg; + *result = pthread_mutex_trylock (&mutex); + return NULL; +} + +static void +run_test (bool pshared, bool pi, int type) +{ + printf ("info: pshared=%d pi=%d type=%d\n", pshared, pi, type); + + pthread_mutexattr_t attr; + xpthread_mutexattr_init (&attr); + xpthread_mutexattr_setrobust (&attr, PTHREAD_MUTEX_ROBUST); + xpthread_mutexattr_settype (&attr, type); + if (pshared) + xpthread_mutexattr_setpshared (&attr, PTHREAD_PROCESS_SHARED); + if (pi) + xpthread_mutexattr_setprotocol (&attr, PTHREAD_PRIO_INHERIT); + + int init_result = pthread_mutex_init (&mutex, &attr); + xpthread_mutexattr_destroy (&attr); + if (pi && init_result == ENOTSUP) + { + puts ("info: PI robust mutexes not supported; skipping this combination"); + return; + } + TEST_COMPARE (init_result, 0); + if (init_result != 0) + return; + + /* The owner dies, and its successor unlocks without making the mutex + consistent. All subsequent lock attempts must fail. */ + xpthread_join (xpthread_create (NULL, lock_and_exit, NULL)); + TEST_COMPARE (pthread_mutex_lock (&mutex), EOWNERDEAD); + TEST_COMPARE (pthread_mutex_unlock (&mutex), 0); + + TEST_COMPARE (pthread_mutex_lock (&mutex), ENOTRECOVERABLE); + TEST_COMPARE (pthread_mutex_trylock (&mutex), ENOTRECOVERABLE); + /* With a recursive mutex, an incorrectly retained lock can return 0 + rather than EBUSY on a second trylock by the same thread. */ + TEST_COMPARE (pthread_mutex_trylock (&mutex), ENOTRECOVERABLE); + + int result = -1; + xpthread_join (xpthread_create (NULL, trylock_in_thread, &result)); + TEST_COMPARE (result, ENOTRECOVERABLE); + + /* A bounded lock attempt detects a lock word retained by trylock. */ + struct timespec timeout = timespec_add (xclock_now (CLOCK_REALTIME), + make_timespec (1, 0)); + TEST_COMPARE (pthread_mutex_timedlock (&mutex, &timeout), ENOTRECOVERABLE); + TEST_COMPARE (pthread_mutex_destroy (&mutex), 0); +} + +static int +do_test (void) +{ + static const int types[] = { + PTHREAD_MUTEX_NORMAL, PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_ERRORCHECK + }; + + for (size_t index = 0; index < sizeof (types) / sizeof (types[0]); ++index) + for (int pshared = 0; pshared < 2; ++pshared) + for (int pi = 0; pi < 2; ++pi) + run_test (pshared, pi, types[index]); + return 0; +} + +#include