From 7f107ab205bc8b7015491800947af22974b4f828 Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Fri, 23 Feb 2024 11:39:56 -0800 Subject: [PATCH] Fix dup in nodefs Backport of emscripten-core/emscripten#21399. Resolves #4541 --- ...s-by-refcounting-nodefs-file-descrip.patch | 166 ++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 emsdk/patches/0001-Fix-dup-in-nodefs-by-refcounting-nodefs-file-descrip.patch diff --git a/emsdk/patches/0001-Fix-dup-in-nodefs-by-refcounting-nodefs-file-descrip.patch b/emsdk/patches/0001-Fix-dup-in-nodefs-by-refcounting-nodefs-file-descrip.patch new file mode 100644 index 00000000000..ebef6f3e2bb --- /dev/null +++ b/emsdk/patches/0001-Fix-dup-in-nodefs-by-refcounting-nodefs-file-descrip.patch @@ -0,0 +1,166 @@ +From 135baa3d4cc211c0145d2e1df116e39f60df4f91 Mon Sep 17 00:00:00 2001 +From: Hood Chatham +Date: Thu, 22 Feb 2024 21:47:13 -0800 +Subject: [PATCH] Fix dup in nodefs by refcounting nodefs file descriptors + (#21399) + +--- + src/library_fs.js | 5 +++++ + src/library_nodefs.js | 6 +++++- + src/library_syscall.js | 6 +++--- + test/fs/test_nodefs_dup.c | 45 +++++++++++++++++++++++++++++++++++++++ + test/test_core.py | 8 +++++++ + 5 files changed, 66 insertions(+), 4 deletions(-) + create mode 100644 test/fs/test_nodefs_dup.c + +diff --git a/src/library_fs.js b/src/library_fs.js +index f5d16b86c..379e65268 100644 +--- a/src/library_fs.js ++++ b/src/library_fs.js +@@ -471,6 +471,11 @@ FS.staticInit();` + + closeStream(fd) { + FS.streams[fd] = null; + }, ++ dupStream(origStream, fd = -1) { ++ var stream = FS.createStream(origStream, fd); ++ stream.stream_ops?.dup?.(stream); ++ return stream; ++ }, + + // + // devices +diff --git a/src/library_nodefs.js b/src/library_nodefs.js +index 81864ffcc..ace50458c 100644 +--- a/src/library_nodefs.js ++++ b/src/library_nodefs.js +@@ -251,6 +251,7 @@ addToLibrary({ + var path = NODEFS.realPath(stream.node); + try { + if (FS.isFile(stream.node.mode)) { ++ stream.shared.refcount = 1; + stream.nfd = fs.openSync(path, NODEFS.flagsForNode(stream.flags)); + } + } catch (e) { +@@ -260,7 +261,7 @@ addToLibrary({ + }, + close(stream) { + try { +- if (FS.isFile(stream.node.mode) && stream.nfd) { ++ if (FS.isFile(stream.node.mode) && stream.nfd && --stream.shared.refcount === 0) { + fs.closeSync(stream.nfd); + } + } catch (e) { +@@ -268,6 +269,9 @@ addToLibrary({ + throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); + } + }, ++ dup(stream) { ++ stream.shared.refcount++; ++ }, + read(stream, buffer, offset, length, position) { + // Node.js < 6 compatibility: node errors on 0 length reads + if (length === 0) return 0; +diff --git a/src/library_syscall.js b/src/library_syscall.js +index b078bd71c..69ea6f8b2 100644 +--- a/src/library_syscall.js ++++ b/src/library_syscall.js +@@ -183,7 +183,7 @@ var SyscallsLibrary = { + }, + __syscall_dup: (fd) => { + var old = SYSCALLS.getStreamFromFD(fd); +- return FS.createStream(old).fd; ++ return FS.dupStream(old).fd; + }, + __syscall_pipe__deps: ['$PIPEFS'], + __syscall_pipe: (fdPtr) => { +@@ -760,7 +760,7 @@ var SyscallsLibrary = { + arg++; + } + var newStream; +- newStream = FS.createStream(stream, arg); ++ newStream = FS.dupStream(stream, arg); + return newStream.fd; + } + case {{{ cDefs.F_GETFD }}}: +@@ -1007,7 +1007,7 @@ var SyscallsLibrary = { + if (old.fd === newfd) return -{{{ cDefs.EINVAL }}}; + var existing = FS.getStream(newfd); + if (existing) FS.close(existing); +- return FS.createStream(old, newfd).fd; ++ return FS.dupStream(old, newfd).fd; + }, + }; + +diff --git a/test/fs/test_nodefs_dup.c b/test/fs/test_nodefs_dup.c +new file mode 100644 +index 000000000..abf34935b +--- /dev/null ++++ b/test/fs/test_nodefs_dup.c +@@ -0,0 +1,45 @@ ++/* ++ * Copyright 2018 The Emscripten Authors. All rights reserved. ++ * Emscripten is available under two separate licenses, the MIT license and the ++ * University of Illinois/NCSA Open Source License. Both these licenses can be ++ * found in the LICENSE file. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef NODERAWFS ++#define CWD "" ++#else ++#define CWD "/working/" ++#endif ++ ++int main(void) ++{ ++ EM_ASM( ++#ifdef NODERAWFS ++ FS.close(FS.open('test.txt', 'w')); ++#else ++ FS.mkdir('/working'); ++ FS.mount(NODEFS, {root: '.'}, '/working'); ++ FS.close(FS.open('/working/test.txt', 'w')); ++#endif ++ ); ++ int fd1 = open(CWD "test.txt", O_WRONLY); ++ int fd2 = dup(fd1); ++ int fd3 = fcntl(fd1, F_DUPFD_CLOEXEC, 0); ++ ++ assert(fd1 == 3); ++ assert(fd2 == 4); ++ assert(fd3 == 5); ++ assert(close(fd1) == 0); ++ assert(write(fd2, "abcdef", 6) == 6); ++ assert(close(fd2) == 0); ++ assert(write(fd3, "ghijkl", 6) == 6); ++ assert(close(fd3) == 0); ++ printf("success\n"); ++ return 0; ++} +diff --git a/test/test_core.py b/test/test_core.py +index 3f21eb5ef..f304f1366 100644 +--- a/test/test_core.py ++++ b/test/test_core.py +@@ -5745,6 +5745,14 @@ Module = { + self.emcc_args += ['-lnodefs.js'] + self.do_runf('fs/test_nodefs_cloexec.c', 'success') + ++ @also_with_noderawfs ++ @requires_node ++ def test_fs_nodefs_dup(self): ++ if self.get_setting('WASMFS'): ++ self.set_setting('FORCE_FILESYSTEM') ++ self.emcc_args += ['-lnodefs.js'] ++ self.do_runf('fs/test_nodefs_dup.c', 'success') ++ + @requires_node + def test_fs_nodefs_home(self): + self.set_setting('FORCE_FILESYSTEM') +-- +2.34.1 +