NetBSD-Bugs archive

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

kern/57659: closing pipe writefd fails to wake concurrent write on same writefd



>Number:         57659
>Category:       kern
>Synopsis:       closing pipe writefd fails to wake concurrent write on same writefd
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Oct 15 11:05:00 +0000 2023
>Originator:     Taylor R Campbell
>Release:        current
>Organization:
The NetBSD Fdation
>Environment:
>Description:
If a write system call on a pipe's writefd is blocking because the pipe is full, a concurrent close system call must wake the write system call and cause it to fail with EBADF.

But it doesn't; the write system call seems to hang indefinitely.

This happens before and after sys_pipe.c 1.165:

https://mail-index.netbsd.org/source-changes/2023/10/13/msg148107.html
>How-To-Repeat:
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>

pthread_barrier_t barrier;
int fd;

static void
waitforbarrier(const char *caller)
{
	int error;

	error = pthread_barrier_wait(&barrier);
	switch (error) {
	case 0:
	case PTHREAD_BARRIER_SERIAL_THREAD:
		break;
	default:
		errc(1, error, "%s: pthread_barrier_wait", caller);
	}
}

static void *
start(void *cookie)
{
	static const char buf[1024*1024]; /* XXX >BIG_PIPE_SIZE */
	ssize_t nwrit;

	waitforbarrier("user");

	nwrit = write(fd, buf, sizeof(buf));
	if (nwrit != -1)    /* buffer filled, try more */
		nwrit = write(fd, buf, sizeof(buf));
	assert(nwrit == -1);
	assert(errno == EBADF);

	return NULL;
}

int
main(void)
{
	int p[2];
	pthread_t t;
	int error;

	if (pipe(p) == -1)
		err(1, "pipe");
	fd = p[1];

	error = pthread_barrier_init(&barrier, NULL, 2);
	if (error)
		errc(1, error, "pthread_barrier_init");
	error = pthread_create(&t, NULL, &start, NULL);
	if (error)
		errc(1, error, "pthread_create");
	waitforbarrier("closer");
	sleep(1);
	alarm(1);
	if (close(fd) == -1)
		err(1, "close");
	error = pthread_join(t, NULL);
	if (error)
		errc(1, error, "pthread_join");

	return 0;
}

>Fix:
Yes, please!



Home | Main Index | Thread Index | Old Index