-
-
Notifications
You must be signed in to change notification settings - Fork 33.8k
Description
Version
v22.14.0
Platform
Microsoft Windows NT 10.0.19045.0 x64
Subsystem
node::fs
What steps will reproduce the bug?
Open a file with ReadFileUtf8() using a path (not a file handle).
How often does it reproduce? Is there a required condition?
Every time, including loading JavaScript files for execution.
What is the expected behavior? Why is that the expected behavior?
Calling readFileSync() with an encoding of UTF-8 should not permanently increase the amount of rss memory being used by node. It's (hopefully) the expected behavior because memory leaks are bad.
What do you see instead?
Calling will cause Node's memory usage to go up indefinitely.
This was discovered when a process using node:worker_threads would continuously increase it's memory consumption until it was forcibly closed. JavaScript debug tools showed that the managed heap's memory usage was constant, but the rss memory usage kept rising. Debugging the node runtime showed that loading modules was calling the underlying ReadFileUtf8 method. The process that was showing this memory leak was not caching workers and was re-loading all code files each time a worker thread was created.
Minimum code example:
import { readFileSync } from 'node:fs';
const options = { encoding: 'utf-8' };
for (let i = 1; true; i++) {
readFileSync('./empty.txt', options);
if (i % 1000 === 0) {
i = 0;
gc();
}
}Output from process.memoryUsage():
2025-04-08 20:23:38: rss - 357.03 MB
2025-04-08 20:23:38: heapTotal - 7.03 MB
2025-04-08 20:23:38: heapUsed - 4.28 MB
2025-04-08 20:23:38: external - 1.73 MB
Additional information
This is my best guess at the bug. I'm like 85% sure of what's going, but this is the first time I'm looking at the NodeJS codebase.
Allocation:
void ReadFileUtf8(const FunctionCallbackInfo<Value>& args)callsuv_fs_openwhich callsfs__capture_path.fs__capture_pathallocates a UTF16 buffer and assigns it touv_fs_s.file.pathw.uv_fs_s.fileis a union type with the definition:union { WCHAR* pathw; int fd; }
Corruption
uv_file file;is allocated and assigned the return value fromuv_fs_open.ReadFileUtf8callsuv_fs_readpassing in the file handlefile.uv_fs_readoverwrites the least significant half ofuv_fs_s.file.pathwwith this callreq->file.fd = fd;.- The pointer to the buffer formerly assigned to
uv_fs_s.file.pathwis lost.
