Fix some bugs with dup2() and ZipOS

On UNIX if dup2(newfd) was a ZipOS file descriptor, then its resources
weren't being released, and the newly created file descriptor would be
mistaken for ZipOS due to its memory not being cleared. On Windows, an
issue also existed relating to newfd resources not being released.
This commit is contained in:
Justine Tunney 2023-11-30 10:10:02 -08:00
parent 26c70e08bf
commit 4b7ba9a4c5
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
4 changed files with 36 additions and 3 deletions

View file

@ -24,9 +24,11 @@
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/weaken.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/zipos.internal.h"
#include "libc/sock/internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
@ -57,9 +59,13 @@ static textwindows int sys_dup_nt_impl(int oldfd, int newfd, int flags,
return -1;
}
if (g_fds.p[newfd].kind) {
if (g_fds.p[newfd].kind == kFdZip) {
_weaken(__zipos_close)(newfd);
} else {
sys_close_nt(newfd, newfd);
}
}
}
if (DuplicateHandle(GetCurrentProcess(), g_fds.p[oldfd].handle,
GetCurrentProcess(), &handle, 0, true,

View file

@ -18,12 +18,15 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/runtime/zipos.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
/**
@ -74,6 +77,11 @@ int dup2(int oldfd, int newfd) {
#endif
} else if (!IsWindows()) {
rc = sys_dup2(oldfd, newfd, 0);
if (rc != -1 && oldfd != newfd && __isfdkind(newfd, kFdZip) && !__vforked) {
_weaken(__zipos_free)(
(struct ZiposHandle *)(intptr_t)g_fds.p[newfd].handle);
bzero(g_fds.p + newfd, sizeof(*g_fds.p));
}
} else if (newfd < 0) {
rc = ebadf();
} else if (oldfd == newfd) {

View file

@ -18,12 +18,15 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/runtime/zipos.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
@ -71,6 +74,11 @@ int dup3(int oldfd, int newfd, int flags) {
rc = enotsup();
} else if (!IsWindows()) {
rc = sys_dup3(oldfd, newfd, flags);
if (rc != -1 && __isfdkind(newfd, kFdZip) && !__vforked) {
_weaken(__zipos_free)(
(struct ZiposHandle *)(intptr_t)g_fds.p[newfd].handle);
bzero(g_fds.p + newfd, sizeof(*g_fds.p));
}
} else {
rc = sys_dup_nt(oldfd, newfd, flags, -1);
}

View file

@ -33,6 +33,8 @@
#include "libc/testlib/testlib.h"
#include "libc/x/xspawn.h"
__static_yoink("libc/testlib/hyperion.txt");
void SetUpOnce(void) {
testlib_enable_tmp_setup_teardown();
}
@ -50,7 +52,6 @@ static textstartup void TestInit(int argc, char **argv) {
const void *const TestCtor[] initarray = {TestInit};
#if 0
TEST(dup, ebadf) {
ASSERT_SYS(EBADF, -1, dup(-1));
ASSERT_SYS(EBADF, -1, dup2(-1, 0));
@ -72,7 +73,17 @@ TEST(dup, bigNumber) {
ASSERT_SYS(0, 100, dup2(0, 100));
ASSERT_SYS(0, 0, close(100));
}
#endif
TEST(dup2, zipos) {
ASSERT_SYS(0, 3, creat("real", 0644));
ASSERT_SYS(0, 4, open("/zip/libc/testlib/hyperion.txt", O_RDONLY));
ASSERT_SYS(0, 2, write(3, "hi", 2));
ASSERT_SYS(EBADF, -1, write(4, "hi", 2));
ASSERT_SYS(0, 4, dup2(3, 4));
ASSERT_SYS(0, 2, write(4, "hi", 2));
ASSERT_SYS(0, 0, close(4));
ASSERT_SYS(0, 0, close(3));
}
#ifdef __x86_64__
TEST(dup, clearsCloexecFlag) {