NetBSD-Bugs archive

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

kern/59586: sigwaitinfo() returns ECANCELED instead of EINTR - POSIX compliance violation



>Number:         59586
>Category:       kern
>Synopsis:       sigwaitinfo() returns ECANCELED instead of EINTR - POSIX compliance violation
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Aug 10 21:55:00 +0000 2025
>Originator:     Furkan Onder
>Release:        NetBSD 10.0
>Organization:
CPython
>Environment:
NetBSD home.localhost 10.0 NetBSD 10.0 (GENERIC) #0: Thu Mar 28 08:33:33 UTC 2024  mkrepro%mkrepro.NetBSD.org@localhost:/usr/src/sys/arch/amd64/compile/GENERIC amd64
>Description:
NetBSD's implementation of sigwaitinfo() violates the POSIX standard by returning errno = ECANCELED (87) instead of errno = EINTR (4)
when the function is interrupted by an unblocked, caught signal that is not in the specified wait set.

This issue was discovered through Python's comprehensive signal handling tests (https://github.com/python/cpython/issues/137490)
where the test suite expects EINTR but receives ECANCELED, causing test failure.

A review of NetBSD's manual pages reveals that ECANCELED is documented for several functions including aio_cancel, strtou, 
errno, aio_write, timerfd_create and strtoi. However, the sigwaitinfo manual page makes no mention of ECANCELED as a possible return value.

Critical Questions for NetBSD Developers
- Is repeating sigwaitinfo() after getting ECANCELED safe?
- What other signal-related functions return ECANCELED instead of EINTR?
- Is this behavior documented anywhere as a NetBSD-specific behavior?
>How-To-Repeat:
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

volatile sig_atomic_t got_sigalrm = 0;

void sigalrm_handler(int sig) {
    got_sigalrm = 1;
    printf("SIGALRM handler called\n");
}

int main() {
    printf("sigwaitinfo interruption test\n");
    
    sigset_t sigset;
    siginfo_t info;
    int target_signal = SIGUSR1;
    
    // Set SIGALRM handler
    struct sigaction sa = {0};
    sa.sa_handler = sigalrm_handler;
    sigaction(SIGALRM, &sa, NULL);
    
    // Block SIGUSR1 and save old mask
    sigemptyset(&sigset);
    sigaddset(&sigset, target_signal);
    pthread_sigmask(SIG_BLOCK, &sigset, NULL);
    
    printf("Blocked SIGUSR1, waiting with sigwaitinfo...\n");
    
    pid_t pid = fork();
    if (pid == 0) {
        sleep(1);
        printf("Child: sending SIGALRM to interrupt parent\n");
        kill(getppid(), SIGALRM);
        exit(0);
    }
    
    printf("Parent: calling sigwaitinfo([SIGUSR1])...\n");
    int result = sigwaitinfo(&sigset, &info);
    
    if (result == -1) {
        printf("sigwaitinfo failed: errno = %d (%s)\n", errno, strerror(errno));
        printf("Expected: errno = 4 (EINTR)\n");
        printf("Actual:   errno = %d (%s)\n", errno, strerror(errno));
    }
    
    printf("SIGALRM handler was called: %s\n", got_sigalrm ? "yes" : "no");
    
    int status;
    waitpid(pid, &status, 0);
    printf("Child exited with status: %d\n", WEXITSTATUS(status));
    
    return 0;
}

gcc -o sigwaitinfo_test sigwaitinfo_test.c
./sigwaitinfo_test

Expected Output (POSIX-compliant systems like Linux):

sigwaitinfo interruption test
Blocked SIGUSR1, waiting with sigwaitinfo...
Parent: calling sigwaitinfo([SIGUSR1])...
Child: sending SIGALRM to interrupt parent
SIGALRM handler called
sigwaitinfo failed: errno = 4 (Interrupted system call)
Expected: errno = 4 (EINTR)
Actual:   errno = 4 (Interrupted system call)
SIGALRM handler was called: yes
Child exited with status: 0

Actual Output on NetBSD 10.0:

sigwaitinfo interruption test
Blocked SIGUSR1, waiting with sigwaitinfo...
Parent: calling sigwaitinfo([SIGUSR1])...
Child: sending SIGALRM to interrupt parent
SIGALRM handler called
sigwaitinfo failed: errno = 87 (Operation canceled)
Expected: errno = 4 (EINTR)
Actual:   errno = 87 (Operation canceled)
SIGALRM handler was called: yes
Child exited with status: 0
>Fix:



Home | Main Index | Thread Index | Old Index