Package: libc6
Version: 2.41-12+deb13u3
Severity: normal

A standalone pthread reproducer shows unexpected behavior for a mutex
configured with PTHREAD_MUTEX_RECURSIVE and PTHREAD_MUTEX_ROBUST.

An owner thread exits while holding the mutex. The next thread receives
EOWNERDEAD and unlocks without calling pthread_mutex_consistent().
The mutex should then remain permanently unrecoverable.

Expected:
Both subsequent pthread_mutex_trylock() calls return ENOTRECOVERABLE.

Observed:
The first returns ENOTRECOVERABLE (131), but the second returns success (0).

Build:
gcc -std=c11 -D_POSIX_C_SOURCE=200809L -Wall -Wextra -pthread repro.c -o repro

Run:
./repro

Output:
After owner death: 130 - expected 130 (Owner died)
First retry:  131 - expected 131 (State not recoverable)
Second retry: 0 - expected 131 (State not recoverable)

The reproducer exits with status 1. Source is attached.
An already expired pthread_mutex_timedlock() consistently returned
ENOTRECOVERABLE in a separate local test.

Environment:
dpkg-query -W libc6 libc6-dev gcc
gcc     4:14.2.0-1
libc6:amd64     2.41-12+deb13u4
libc6-dev:amd64 2.41-12+deb13u4
dpkg --print-architecture
amd64
getconf GNU_LIBC_VERSION
glibc 2.41
gcc --version
gcc (Debian 14.2.0-19) 14.2.0
Copyright (C) 2024 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
uname -a
Linux 345f1f893561 6.18.54.1-microsoft-standard-WSL2 #1 SMP PREEMPT_DYNAMIC Tue 
Oct  6 19:13:07 UTC 2026 x86_64 GNU/Linux
cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 13 (trixie)"
NAME="Debian GNU/Linux"
VERSION_ID="13"
VERSION="13 (trixie)"
VERSION_CODENAME=trixie
DEBIAN_VERSION_FULL=13.7
ID=debian
HOME_URL=https://www.debian.org/
SUPPORT_URL=https://www.debian.org/support
BUG_REPORT_URL=https://bugs.debian.org/


Mit freundlichen Grüßen / Kind regards

i. A. Tobias Schülein
Team Leader OS RT System
R&D ASF

KUKA Deutschland GmbH   Zugspitzstraße 140, 86165 Augsburg / Germany   
www.kuka.com<http://www.kuka.com/>
[email protected]<mailto:[email protected]>   T +49 821 797‑3925



KUKA Deutschland GmbH   Board of Directors: Michael Jürgens (Chairman), Johan 
Naten, Hui Zhang   Registered Office: Augsburg HRB 14914

This e-mail may contain confidential and/or privileged information. If you are 
not the intended recipient (or have received this e-mail in error) please 
notify the sender immediately and destroy this e-mail. Any unauthorized 
copying, disclosure or distribution of contents of this e-mail is strictly 
forbidden.

Please consider the environment before printing this e-mail.
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static pthread_mutex_t mutex;

static void check(int error)
{
    if (error != 0) {
        fprintf(stderr, "Unexpected pthread error: %d\n", error);
        exit(2);
    }
}

static void *owner(void *unused)
{
    (void)unused;
    check(pthread_mutex_lock(&mutex));
    return NULL; /* Exit while holding the mutex. */
}

int main(void)
{
    pthread_mutexattr_t attributes;
    check(pthread_mutexattr_init(&attributes));
    check(pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE));
    check(pthread_mutexattr_setrobust(&attributes, PTHREAD_MUTEX_ROBUST));
    check(pthread_mutex_init(&mutex, &attributes));
    check(pthread_mutexattr_destroy(&attributes));

    pthread_t thread;
    check(pthread_create(&thread, NULL, owner, NULL));
    check(pthread_join(thread, NULL));

    int abandoned = pthread_mutex_trylock(&mutex);
    printf("After owner death: %d - expected %d (%s)\n", abandoned, EOWNERDEAD, 
strerror(EOWNERDEAD));
    if (abandoned != EOWNERDEAD)
        return 2;

    /* Unlock without making consistent, marking the mutex unrecoverable. */
    check(pthread_mutex_unlock(&mutex));

    int first = pthread_mutex_trylock(&mutex);
    int second = pthread_mutex_trylock(&mutex);
    printf("First retry:  %d - expected %d (%s)\n", first, ENOTRECOVERABLE, 
strerror(ENOTRECOVERABLE));
    printf("Second retry: %d - expected %d (%s)\n", second, ENOTRECOVERABLE, 
strerror(ENOTRECOVERABLE));
    return first == ENOTRECOVERABLE && second == ENOTRECOVERABLE ? 0 : 1;
}

Reply via email to