NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
lib/58266: dup3 behavior differs from FreeBSD, OpenBSD, and glibc.
>Number: 58266
>Category: lib
>Synopsis: dup3 behavior differs from FreeBSD, OpenBSD, and glibc.
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: lib-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sat May 18 23:05:00 +0000 2024
>Originator: Collin Funk
>Release: NetBSD 10.0 amd64
>Organization:
GNU
>Environment:
NetBSD netbsd 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:
Hello,
A CI job on NetBSD 9.0 and NetBSD 10.0 caught some test failures in Gnulib, one of which being dup3 [1]. I've reproduced it on a NetBSD 10.0 virtual machine and found a fix for Gnulib.
However, when looking into the test failure I noticed that dup3 on NetBSD behaves differently than FreeBSD, OpenBSD, and glibc.
>From the Linux man pages describing the return value [2]:
If oldfd equals newfd, then dup3() fails with the error EINVAL.
The man pages for FreeBSD and OpenBSD describe this same behavior [3] [4].
On NetBSD the man pages describe a different behavior [5]:
These calls return the new file descriptor value. In the case of dup2()
and dup3() this is always the same as newfd. If an error occurs, the
value -1 is returned and errno is set to indicate what happened.
I'm not sure if there was a reasoning behind this difference, so I figured it was worth reporting. I've taken the test case that fails and put it in a sample program attached to help reproduce the behavior. All the other test cases in Gnulib seem to work as expected besides that one.
[1] https://lists.gnu.org/archive/html/bug-gnulib/2024-05/msg00271.html
[2] https://man7.org/linux/man-pages/man2/dup3.2.html
[3] https://man.freebsd.org/cgi/man.cgi?query=dup3&sektion=3
[4] https://man.openbsd.org/dup.2
[5] https://man.netbsd.org/dup3.2
>How-To-Repeat:
I've extracted the relevant test case and placed it in this program:
=====================================================
#define _GNU_SOURCE 1
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
int
main (void)
{
const char *file = "test-dup3.tmp";
int fd = open (file, O_CREAT | O_TRUNC | O_RDWR, 0600);
int result = dup3 (fd, fd, 0);
int saved_errno = errno;
/* Check that the file could be created. */
if (fd == -1)
abort ();
/* Cleanup the file and restore errno. */
(void) unlink (file);
errno = saved_errno;
/* Expect dup3 to fail with errno == EINVAL. */
if (result != -1)
{
(void) close (result);
fprintf (stderr, "dup3 (fd, fd, 0) should fail with EINVAL\n");
abort ();
}
printf ("%s\n", strerror (errno));
return 0;
}
=====================================================
Here are the results on different platforms. Unfortunately, I don't have access to an OpenBSD machine but I expect it to behave like GNU/Linux and FreeBSD.
On GNU/Linux and FreeBSD:
$ gcc main.c
$ ./a.out
Invalid argument
$ echo $?
0
On NetBSD:
$ gcc main.c
$ ./a.out
dup3 (fd, fd, 0) should fail with EINVAL
Abort trap (core dumped)
>Fix:
I believe that a small change in the 'dodup' function in src/sys/kern/sys_descrip.c should change the behavior to align with the other systems. I am not too familiar with NetBSD though so I may be missing something.
Home |
Main Index |
Thread Index |
Old Index