Bug Summary

File:out/../src/node_dir.cc
Warning:line 345, column 31
Potential leak of memory pointed to by 'handle'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name node_dir.cc -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/home/maurizio/node-v18.6.0/out -resource-dir /usr/local/lib/clang/16.0.0 -D V8_DEPRECATION_WARNINGS -D V8_IMMINENT_DEPRECATION_WARNINGS -D _GLIBCXX_USE_CXX11_ABI=1 -D NODE_OPENSSL_CONF_NAME=nodejs_conf -D NODE_OPENSSL_HAS_QUIC -D __STDC_FORMAT_MACROS -D OPENSSL_NO_PINSHARED -D OPENSSL_THREADS -D NODE_ARCH="x64" -D NODE_PLATFORM="linux" -D NODE_WANT_INTERNALS=1 -D V8_DEPRECATION_WARNINGS=1 -D NODE_OPENSSL_SYSTEM_CERT_PATH="" -D NODE_USE_NODE_CODE_CACHE=1 -D HAVE_INSPECTOR=1 -D NODE_ENABLE_LARGE_CODE_PAGES=1 -D __POSIX__ -D NODE_USE_V8_PLATFORM=1 -D NODE_HAVE_I18N_SUPPORT=1 -D HAVE_OPENSSL=1 -D OPENSSL_API_COMPAT=0x10100000L -D UCONFIG_NO_SERVICE=1 -D U_ENABLE_DYLOAD=0 -D U_STATIC_IMPLEMENTATION=1 -D U_HAVE_STD_STRING=1 -D UCONFIG_NO_BREAK_ITERATION=0 -D _LARGEFILE_SOURCE -D _FILE_OFFSET_BITS=64 -D _POSIX_C_SOURCE=200112 -D NGHTTP2_STATICLIB -D NDEBUG -D OPENSSL_USE_NODELETE -D L_ENDIAN -D OPENSSL_BUILDING_OPENSSL -D AES_ASM -D BSAES_ASM -D CMLL_ASM -D ECP_NISTZ256_ASM -D GHASH_ASM -D KECCAK1600_ASM -D MD5_ASM -D OPENSSL_BN_ASM_GF2m -D OPENSSL_BN_ASM_MONT -D OPENSSL_BN_ASM_MONT5 -D OPENSSL_CPUID_OBJ -D OPENSSL_IA32_SSE2 -D PADLOCK_ASM -D POLY1305_ASM -D SHA1_ASM -D SHA256_ASM -D SHA512_ASM -D VPAES_ASM -D WHIRLPOOL_ASM -D X25519_ASM -D OPENSSL_PIC -D NGTCP2_STATICLIB -D NGHTTP3_STATICLIB -I ../src -I /home/maurizio/node-v18.6.0/out/Release/obj/gen -I /home/maurizio/node-v18.6.0/out/Release/obj/gen/include -I /home/maurizio/node-v18.6.0/out/Release/obj/gen/src -I ../deps/googletest/include -I ../deps/histogram/src -I ../deps/uvwasi/include -I ../deps/v8/include -I ../deps/icu-small/source/i18n -I ../deps/icu-small/source/common -I ../deps/zlib -I ../deps/llhttp/include -I ../deps/cares/include -I ../deps/uv/include -I ../deps/nghttp2/lib/includes -I ../deps/brotli/c/include -I ../deps/openssl/openssl/include -I ../deps/openssl/openssl/crypto/include -I ../deps/openssl/config/archs/linux-x86_64/asm/include -I ../deps/openssl/config/archs/linux-x86_64/asm -I ../deps/ngtcp2 -I ../deps/ngtcp2/ngtcp2/lib/includes -I ../deps/ngtcp2/ngtcp2/crypto/includes -I ../deps/ngtcp2/nghttp3/lib/includes -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8 -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/x86_64-redhat-linux -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/backward -internal-isystem /usr/local/lib/clang/16.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-unused-parameter -Wno-unused-parameter -std=gnu++17 -fdeprecated-macro -fdebug-compilation-dir=/home/maurizio/node-v18.6.0/out -ferror-limit 19 -fno-rtti -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-08-22-142216-507842-1 -x c++ ../src/node_dir.cc
1#include "node_dir.h"
2#include "node_external_reference.h"
3#include "node_file-inl.h"
4#include "node_process-inl.h"
5#include "memory_tracker-inl.h"
6#include "util.h"
7
8#include "tracing/trace_event.h"
9
10#include "string_bytes.h"
11
12#include <fcntl.h>
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <cstring>
16#include <cerrno>
17#include <climits>
18
19#include <memory>
20
21namespace node {
22
23namespace fs_dir {
24
25using fs::FSReqAfterScope;
26using fs::FSReqBase;
27using fs::FSReqWrapSync;
28using fs::GetReqWrap;
29
30using v8::Array;
31using v8::Context;
32using v8::FunctionCallbackInfo;
33using v8::FunctionTemplate;
34using v8::HandleScope;
35using v8::Integer;
36using v8::Isolate;
37using v8::Local;
38using v8::MaybeLocal;
39using v8::Null;
40using v8::Number;
41using v8::Object;
42using v8::ObjectTemplate;
43using v8::Value;
44
45#define TRACE_NAME(name)"fs_dir.sync." "name" "fs_dir.sync." #name
46#define GET_TRACE_ENABLED(*node::tracing::TraceEventHelper::GetCategoryGroupEnabled ("node"
"," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync") !=
0)
\
47 (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLEDnode::tracing::TraceEventHelper::GetCategoryGroupEnabled \
48 (TRACING_CATEGORY_NODE2(fs_dir, sync)"node" "," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync") != 0)
49#define FS_DIR_SYNC_TRACE_BEGIN(syscall, ...)if ((*node::tracing::TraceEventHelper::GetCategoryGroupEnabled
("node" "," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync"
) != 0)) do { static std::atomic<intptr_t> trace_event_unique_atomic49
{0}; const uint8_t* trace_event_unique_category_group_enabled49
; trace_event_unique_category_group_enabled49 = reinterpret_cast
<const uint8_t*>((trace_event_unique_atomic49).load());
if (!trace_event_unique_category_group_enabled49) { trace_event_unique_category_group_enabled49
= node::tracing::TraceEventHelper::GetCategoryGroupEnabled("node"
"," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync");
(trace_event_unique_atomic49).store(reinterpret_cast<intptr_t
>( trace_event_unique_category_group_enabled49)); };; if (
*trace_event_unique_category_group_enabled49 & (kEnabledForRecording_CategoryGroupEnabledFlags
| kEnabledForEventCallback_CategoryGroupEnabledFlags)) { node
::tracing::AddTraceEvent( ('B'), trace_event_unique_category_group_enabled49
, "fs_dir.sync." "syscall", node::tracing::kGlobalScope, node
::tracing::kNoId, node::tracing::kNoId, (static_cast<unsigned
int>(0)), ...); } } while (0);
\
50 if (GET_TRACE_ENABLED(*node::tracing::TraceEventHelper::GetCategoryGroupEnabled ("node"
"," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync") !=
0)
) \
51 TRACE_EVENT_BEGIN(TRACING_CATEGORY_NODE2(fs_dir, sync), TRACE_NAME(syscall), \do { static std::atomic<intptr_t> trace_event_unique_atomic52
{0}; const uint8_t* trace_event_unique_category_group_enabled52
; trace_event_unique_category_group_enabled52 = reinterpret_cast
<const uint8_t*>((trace_event_unique_atomic52).load());
if (!trace_event_unique_category_group_enabled52) { trace_event_unique_category_group_enabled52
= node::tracing::TraceEventHelper::GetCategoryGroupEnabled("node"
"," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync");
(trace_event_unique_atomic52).store(reinterpret_cast<intptr_t
>( trace_event_unique_category_group_enabled52)); };; if (
*trace_event_unique_category_group_enabled52 & (kEnabledForRecording_CategoryGroupEnabledFlags
| kEnabledForEventCallback_CategoryGroupEnabledFlags)) { node
::tracing::AddTraceEvent( ('B'), trace_event_unique_category_group_enabled52
, "fs_dir.sync." "syscall", node::tracing::kGlobalScope, node
::tracing::kNoId, node::tracing::kNoId, (static_cast<unsigned
int>(0)), ##__VA_ARGS__); } } while (0)
52 ##__VA_ARGS__)do { static std::atomic<intptr_t> trace_event_unique_atomic52
{0}; const uint8_t* trace_event_unique_category_group_enabled52
; trace_event_unique_category_group_enabled52 = reinterpret_cast
<const uint8_t*>((trace_event_unique_atomic52).load());
if (!trace_event_unique_category_group_enabled52) { trace_event_unique_category_group_enabled52
= node::tracing::TraceEventHelper::GetCategoryGroupEnabled("node"
"," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync");
(trace_event_unique_atomic52).store(reinterpret_cast<intptr_t
>( trace_event_unique_category_group_enabled52)); };; if (
*trace_event_unique_category_group_enabled52 & (kEnabledForRecording_CategoryGroupEnabledFlags
| kEnabledForEventCallback_CategoryGroupEnabledFlags)) { node
::tracing::AddTraceEvent( ('B'), trace_event_unique_category_group_enabled52
, "fs_dir.sync." "syscall", node::tracing::kGlobalScope, node
::tracing::kNoId, node::tracing::kNoId, (static_cast<unsigned
int>(0)), ##__VA_ARGS__); } } while (0)
;
53#define FS_DIR_SYNC_TRACE_END(syscall, ...)if ((*node::tracing::TraceEventHelper::GetCategoryGroupEnabled
("node" "," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync"
) != 0)) do { static std::atomic<intptr_t> trace_event_unique_atomic53
{0}; const uint8_t* trace_event_unique_category_group_enabled53
; trace_event_unique_category_group_enabled53 = reinterpret_cast
<const uint8_t*>((trace_event_unique_atomic53).load());
if (!trace_event_unique_category_group_enabled53) { trace_event_unique_category_group_enabled53
= node::tracing::TraceEventHelper::GetCategoryGroupEnabled("node"
"," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync");
(trace_event_unique_atomic53).store(reinterpret_cast<intptr_t
>( trace_event_unique_category_group_enabled53)); };; if (
*trace_event_unique_category_group_enabled53 & (kEnabledForRecording_CategoryGroupEnabledFlags
| kEnabledForEventCallback_CategoryGroupEnabledFlags)) { node
::tracing::AddTraceEvent( ('E'), trace_event_unique_category_group_enabled53
, "fs_dir.sync." "syscall", node::tracing::kGlobalScope, node
::tracing::kNoId, node::tracing::kNoId, (static_cast<unsigned
int>(0)), ...); } } while (0);
\
54 if (GET_TRACE_ENABLED(*node::tracing::TraceEventHelper::GetCategoryGroupEnabled ("node"
"," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync") !=
0)
) \
55 TRACE_EVENT_END(TRACING_CATEGORY_NODE2(fs_dir, sync), TRACE_NAME(syscall), \do { static std::atomic<intptr_t> trace_event_unique_atomic56
{0}; const uint8_t* trace_event_unique_category_group_enabled56
; trace_event_unique_category_group_enabled56 = reinterpret_cast
<const uint8_t*>((trace_event_unique_atomic56).load());
if (!trace_event_unique_category_group_enabled56) { trace_event_unique_category_group_enabled56
= node::tracing::TraceEventHelper::GetCategoryGroupEnabled("node"
"," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync");
(trace_event_unique_atomic56).store(reinterpret_cast<intptr_t
>( trace_event_unique_category_group_enabled56)); };; if (
*trace_event_unique_category_group_enabled56 & (kEnabledForRecording_CategoryGroupEnabledFlags
| kEnabledForEventCallback_CategoryGroupEnabledFlags)) { node
::tracing::AddTraceEvent( ('E'), trace_event_unique_category_group_enabled56
, "fs_dir.sync." "syscall", node::tracing::kGlobalScope, node
::tracing::kNoId, node::tracing::kNoId, (static_cast<unsigned
int>(0)), ##__VA_ARGS__); } } while (0)
56 ##__VA_ARGS__)do { static std::atomic<intptr_t> trace_event_unique_atomic56
{0}; const uint8_t* trace_event_unique_category_group_enabled56
; trace_event_unique_category_group_enabled56 = reinterpret_cast
<const uint8_t*>((trace_event_unique_atomic56).load());
if (!trace_event_unique_category_group_enabled56) { trace_event_unique_category_group_enabled56
= node::tracing::TraceEventHelper::GetCategoryGroupEnabled("node"
"," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync");
(trace_event_unique_atomic56).store(reinterpret_cast<intptr_t
>( trace_event_unique_category_group_enabled56)); };; if (
*trace_event_unique_category_group_enabled56 & (kEnabledForRecording_CategoryGroupEnabledFlags
| kEnabledForEventCallback_CategoryGroupEnabledFlags)) { node
::tracing::AddTraceEvent( ('E'), trace_event_unique_category_group_enabled56
, "fs_dir.sync." "syscall", node::tracing::kGlobalScope, node
::tracing::kNoId, node::tracing::kNoId, (static_cast<unsigned
int>(0)), ##__VA_ARGS__); } } while (0)
;
57
58DirHandle::DirHandle(Environment* env, Local<Object> obj, uv_dir_t* dir)
59 : AsyncWrap(env, obj, AsyncWrap::PROVIDER_DIRHANDLE),
60 dir_(dir) {
61 MakeWeak();
62
63 dir_->nentries = 0;
64 dir_->dirents = nullptr;
65}
66
67DirHandle* DirHandle::New(Environment* env, uv_dir_t* dir) {
68 Local<Object> obj;
69 if (!env->dir_instance_template()
16
Taking false branch
70 ->NewInstance(env->context())
71 .ToLocal(&obj)) {
72 return nullptr;
73 }
74
75 return new DirHandle(env, obj, dir);
17
Memory is allocated
76}
77
78void DirHandle::New(const FunctionCallbackInfo<Value>& args) {
79 CHECK(args.IsConstructCall())do { if (__builtin_expect(!!(!(args.IsConstructCall())), 0)) {
do { static const node::AssertionInfo args = { "../src/node_dir.cc"
":" "79", "args.IsConstructCall()", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
;
80}
81
82DirHandle::~DirHandle() {
83 CHECK(!closing_)do { if (__builtin_expect(!!(!(!closing_)), 0)) { do { static
const node::AssertionInfo args = { "../src/node_dir.cc" ":" "83"
, "!closing_", __PRETTY_FUNCTION__ }; node::Assert(args); } while
(0); } } while (0)
; // We should not be deleting while explicitly closing!
84 GCClose(); // Close synchronously and emit warning
85 CHECK(closed_)do { if (__builtin_expect(!!(!(closed_)), 0)) { do { static const
node::AssertionInfo args = { "../src/node_dir.cc" ":" "85", "closed_"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
; // We have to be closed at the point
86}
87
88void DirHandle::MemoryInfo(MemoryTracker* tracker) const {
89 tracker->TrackFieldWithSize("dir", sizeof(*dir_));
90}
91
92// Close the directory handle if it hasn't already been closed. A process
93// warning will be emitted using a SetImmediate to avoid calling back to
94// JS during GC. If closing the fd fails at this point, a fatal exception
95// will crash the process immediately.
96inline void DirHandle::GCClose() {
97 if (closed_) return;
98 uv_fs_t req;
99 int ret = uv_fs_closedir(nullptr, &req, dir_, nullptr);
100 uv_fs_req_cleanup(&req);
101 closing_ = false;
102 closed_ = true;
103
104 struct err_detail { int ret; };
105
106 err_detail detail { ret };
107
108 if (ret < 0) {
109 // Do not unref this
110 env()->SetImmediate([detail](Environment* env) {
111 const char* msg = "Closing directory handle on garbage collection failed";
112 // This exception will end up being fatal for the process because
113 // it is being thrown from within the SetImmediate handler and
114 // there is no JS stack to bubble it to. In other words, tearing
115 // down the process is the only reasonable thing we can do here.
116 HandleScope handle_scope(env->isolate());
117 env->ThrowUVException(detail.ret, "close", msg);
118 });
119 return;
120 }
121
122 // If the close was successful, we still want to emit a process warning
123 // to notify that the file descriptor was gc'd. We want to be noisy about
124 // this because not explicitly closing the DirHandle is a bug.
125
126 env()->SetImmediate([](Environment* env) {
127 ProcessEmitWarning(env,
128 "Closing directory handle on garbage collection");
129 }, CallbackFlags::kUnrefed);
130}
131
132void AfterClose(uv_fs_t* req) {
133 FSReqBase* req_wrap = FSReqBase::from_req(req);
134 FSReqAfterScope after(req_wrap, req);
135
136 if (after.Proceed())
137 req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
138}
139
140void DirHandle::Close(const FunctionCallbackInfo<Value>& args) {
141 Environment* env = Environment::GetCurrent(args);
142
143 const int argc = args.Length();
144 CHECK_GE(argc, 1)do { if (__builtin_expect(!!(!((argc) >= (1))), 0)) { do {
static const node::AssertionInfo args = { "../src/node_dir.cc"
":" "144", "(argc) >= (1)", __PRETTY_FUNCTION__ }; node::
Assert(args); } while (0); } } while (0)
;
145
146 DirHandle* dir;
147 ASSIGN_OR_RETURN_UNWRAP(&dir, args.Holder())do { *&dir = static_cast<typename std::remove_reference
<decltype(*&dir)>::type>( BaseObject::FromJSObject
(args.Holder())); if (*&dir == nullptr) return ; } while (
0)
;
148
149 dir->closing_ = false;
150 dir->closed_ = true;
151
152 FSReqBase* req_wrap_async = GetReqWrap(args, 0);
153 if (req_wrap_async != nullptr) { // close(req)
154 AsyncCall(env, req_wrap_async, args, "closedir", UTF8, AfterClose,
155 uv_fs_closedir, dir->dir());
156 } else { // close(undefined, ctx)
157 CHECK_EQ(argc, 2)do { if (__builtin_expect(!!(!((argc) == (2))), 0)) { do { static
const node::AssertionInfo args = { "../src/node_dir.cc" ":" "157"
, "(argc) == (2)", __PRETTY_FUNCTION__ }; node::Assert(args);
} while (0); } } while (0)
;
158 FSReqWrapSync req_wrap_sync;
159 FS_DIR_SYNC_TRACE_BEGIN(closedir)if ((*node::tracing::TraceEventHelper::GetCategoryGroupEnabled
("node" "," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync"
) != 0)) do { static std::atomic<intptr_t> trace_event_unique_atomic159
{0}; const uint8_t* trace_event_unique_category_group_enabled159
; trace_event_unique_category_group_enabled159 = reinterpret_cast
<const uint8_t*>((trace_event_unique_atomic159).load())
; if (!trace_event_unique_category_group_enabled159) { trace_event_unique_category_group_enabled159
= node::tracing::TraceEventHelper::GetCategoryGroupEnabled("node"
"," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync");
(trace_event_unique_atomic159).store(reinterpret_cast<intptr_t
>( trace_event_unique_category_group_enabled159)); };; if (
*trace_event_unique_category_group_enabled159 & (kEnabledForRecording_CategoryGroupEnabledFlags
| kEnabledForEventCallback_CategoryGroupEnabledFlags)) { node
::tracing::AddTraceEvent( ('B'), trace_event_unique_category_group_enabled159
, "fs_dir.sync." "closedir", node::tracing::kGlobalScope, node
::tracing::kNoId, node::tracing::kNoId, (static_cast<unsigned
int>(0))); } } while (0);
;
160 SyncCall(env, args[1], &req_wrap_sync, "closedir", uv_fs_closedir,
161 dir->dir());
162 FS_DIR_SYNC_TRACE_END(closedir)if ((*node::tracing::TraceEventHelper::GetCategoryGroupEnabled
("node" "," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync"
) != 0)) do { static std::atomic<intptr_t> trace_event_unique_atomic162
{0}; const uint8_t* trace_event_unique_category_group_enabled162
; trace_event_unique_category_group_enabled162 = reinterpret_cast
<const uint8_t*>((trace_event_unique_atomic162).load())
; if (!trace_event_unique_category_group_enabled162) { trace_event_unique_category_group_enabled162
= node::tracing::TraceEventHelper::GetCategoryGroupEnabled("node"
"," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync");
(trace_event_unique_atomic162).store(reinterpret_cast<intptr_t
>( trace_event_unique_category_group_enabled162)); };; if (
*trace_event_unique_category_group_enabled162 & (kEnabledForRecording_CategoryGroupEnabledFlags
| kEnabledForEventCallback_CategoryGroupEnabledFlags)) { node
::tracing::AddTraceEvent( ('E'), trace_event_unique_category_group_enabled162
, "fs_dir.sync." "closedir", node::tracing::kGlobalScope, node
::tracing::kNoId, node::tracing::kNoId, (static_cast<unsigned
int>(0))); } } while (0);
;
163 }
164}
165
166static MaybeLocal<Array> DirentListToArray(
167 Environment* env,
168 uv_dirent_t* ents,
169 int num,
170 enum encoding encoding,
171 Local<Value>* err_out) {
172 MaybeStackBuffer<Local<Value>, 64> entries(num * 2);
173
174 // Return an array of all read filenames.
175 int j = 0;
176 for (int i = 0; i < num; i++) {
177 Local<Value> filename;
178 Local<Value> error;
179 const size_t namelen = strlen(ents[i].name);
180 if (!StringBytes::Encode(env->isolate(),
181 ents[i].name,
182 namelen,
183 encoding,
184 &error).ToLocal(&filename)) {
185 *err_out = error;
186 return MaybeLocal<Array>();
187 }
188
189 entries[j++] = filename;
190 entries[j++] = Integer::New(env->isolate(), ents[i].type);
191 }
192
193 return Array::New(env->isolate(), entries.out(), j);
194}
195
196static void AfterDirRead(uv_fs_t* req) {
197 BaseObjectPtr<FSReqBase> req_wrap { FSReqBase::from_req(req) };
198 FSReqAfterScope after(req_wrap.get(), req);
199
200 if (!after.Proceed()) {
201 return;
202 }
203
204 Environment* env = req_wrap->env();
205 Isolate* isolate = env->isolate();
206
207 if (req->result == 0) {
208 // Done
209 Local<Value> done = Null(isolate);
210 after.Clear();
211 req_wrap->Resolve(done);
212 return;
213 }
214
215 uv_dir_t* dir = static_cast<uv_dir_t*>(req->ptr);
216
217 Local<Value> error;
218 Local<Array> js_array;
219 if (!DirentListToArray(env,
220 dir->dirents,
221 static_cast<int>(req->result),
222 req_wrap->encoding(),
223 &error)
224 .ToLocal(&js_array)) {
225 // Clear libuv resources *before* delivering results to JS land because
226 // that can schedule another operation on the same uv_dir_t. Ditto below.
227 after.Clear();
228 return req_wrap->Reject(error);
229 }
230
231 after.Clear();
232 req_wrap->Resolve(js_array);
233}
234
235
236void DirHandle::Read(const FunctionCallbackInfo<Value>& args) {
237 Environment* env = Environment::GetCurrent(args);
238 Isolate* isolate = env->isolate();
239
240 const int argc = args.Length();
241 CHECK_GE(argc, 3)do { if (__builtin_expect(!!(!((argc) >= (3))), 0)) { do {
static const node::AssertionInfo args = { "../src/node_dir.cc"
":" "241", "(argc) >= (3)", __PRETTY_FUNCTION__ }; node::
Assert(args); } while (0); } } while (0)
;
242
243 const enum encoding encoding = ParseEncoding(isolate, args[0], UTF8);
244
245 DirHandle* dir;
246 ASSIGN_OR_RETURN_UNWRAP(&dir, args.Holder())do { *&dir = static_cast<typename std::remove_reference
<decltype(*&dir)>::type>( BaseObject::FromJSObject
(args.Holder())); if (*&dir == nullptr) return ; } while (
0)
;
247
248 CHECK(args[1]->IsNumber())do { if (__builtin_expect(!!(!(args[1]->IsNumber())), 0)) {
do { static const node::AssertionInfo args = { "../src/node_dir.cc"
":" "248", "args[1]->IsNumber()", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
;
249 uint64_t buffer_size = static_cast<uint64_t>(args[1].As<Number>()->Value());
250
251 if (buffer_size != dir->dirents_.size()) {
252 dir->dirents_.resize(buffer_size);
253 dir->dir_->nentries = buffer_size;
254 dir->dir_->dirents = dir->dirents_.data();
255 }
256
257 FSReqBase* req_wrap_async = GetReqWrap(args, 2);
258 if (req_wrap_async != nullptr) { // dir.read(encoding, bufferSize, req)
259 AsyncCall(env, req_wrap_async, args, "readdir", encoding,
260 AfterDirRead, uv_fs_readdir, dir->dir());
261 } else { // dir.read(encoding, bufferSize, undefined, ctx)
262 CHECK_EQ(argc, 4)do { if (__builtin_expect(!!(!((argc) == (4))), 0)) { do { static
const node::AssertionInfo args = { "../src/node_dir.cc" ":" "262"
, "(argc) == (4)", __PRETTY_FUNCTION__ }; node::Assert(args);
} while (0); } } while (0)
;
263 FSReqWrapSync req_wrap_sync;
264 FS_DIR_SYNC_TRACE_BEGIN(readdir)if ((*node::tracing::TraceEventHelper::GetCategoryGroupEnabled
("node" "," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync"
) != 0)) do { static std::atomic<intptr_t> trace_event_unique_atomic264
{0}; const uint8_t* trace_event_unique_category_group_enabled264
; trace_event_unique_category_group_enabled264 = reinterpret_cast
<const uint8_t*>((trace_event_unique_atomic264).load())
; if (!trace_event_unique_category_group_enabled264) { trace_event_unique_category_group_enabled264
= node::tracing::TraceEventHelper::GetCategoryGroupEnabled("node"
"," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync");
(trace_event_unique_atomic264).store(reinterpret_cast<intptr_t
>( trace_event_unique_category_group_enabled264)); };; if (
*trace_event_unique_category_group_enabled264 & (kEnabledForRecording_CategoryGroupEnabledFlags
| kEnabledForEventCallback_CategoryGroupEnabledFlags)) { node
::tracing::AddTraceEvent( ('B'), trace_event_unique_category_group_enabled264
, "fs_dir.sync." "readdir", node::tracing::kGlobalScope, node
::tracing::kNoId, node::tracing::kNoId, (static_cast<unsigned
int>(0))); } } while (0);
;
265 int err = SyncCall(env, args[3], &req_wrap_sync, "readdir", uv_fs_readdir,
266 dir->dir());
267 FS_DIR_SYNC_TRACE_END(readdir)if ((*node::tracing::TraceEventHelper::GetCategoryGroupEnabled
("node" "," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync"
) != 0)) do { static std::atomic<intptr_t> trace_event_unique_atomic267
{0}; const uint8_t* trace_event_unique_category_group_enabled267
; trace_event_unique_category_group_enabled267 = reinterpret_cast
<const uint8_t*>((trace_event_unique_atomic267).load())
; if (!trace_event_unique_category_group_enabled267) { trace_event_unique_category_group_enabled267
= node::tracing::TraceEventHelper::GetCategoryGroupEnabled("node"
"," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync");
(trace_event_unique_atomic267).store(reinterpret_cast<intptr_t
>( trace_event_unique_category_group_enabled267)); };; if (
*trace_event_unique_category_group_enabled267 & (kEnabledForRecording_CategoryGroupEnabledFlags
| kEnabledForEventCallback_CategoryGroupEnabledFlags)) { node
::tracing::AddTraceEvent( ('E'), trace_event_unique_category_group_enabled267
, "fs_dir.sync." "readdir", node::tracing::kGlobalScope, node
::tracing::kNoId, node::tracing::kNoId, (static_cast<unsigned
int>(0))); } } while (0);
;
268 if (err < 0) {
269 return; // syscall failed, no need to continue, error info is in ctx
270 }
271
272 if (req_wrap_sync.req.result == 0) {
273 // Done
274 Local<Value> done = Null(isolate);
275 args.GetReturnValue().Set(done);
276 return;
277 }
278
279 CHECK_GE(req_wrap_sync.req.result, 0)do { if (__builtin_expect(!!(!((req_wrap_sync.req.result) >=
(0))), 0)) { do { static const node::AssertionInfo args = { "../src/node_dir.cc"
":" "279", "(req_wrap_sync.req.result) >= (0)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
280
281 Local<Value> error;
282 Local<Array> js_array;
283 if (!DirentListToArray(env,
284 dir->dir()->dirents,
285 static_cast<int>(req_wrap_sync.req.result),
286 encoding,
287 &error)
288 .ToLocal(&js_array)) {
289 Local<Object> ctx = args[2].As<Object>();
290 USE(ctx->Set(env->context(), env->error_string(), error));
291 return;
292 }
293
294 args.GetReturnValue().Set(js_array);
295 }
296}
297
298void AfterOpenDir(uv_fs_t* req) {
299 FSReqBase* req_wrap = FSReqBase::from_req(req);
300 FSReqAfterScope after(req_wrap, req);
301
302 if (!after.Proceed()) {
303 return;
304 }
305
306 Environment* env = req_wrap->env();
307
308 uv_dir_t* dir = static_cast<uv_dir_t*>(req->ptr);
309 DirHandle* handle = DirHandle::New(env, dir);
310
311 req_wrap->Resolve(handle->object().As<Value>());
312}
313
314static void OpenDir(const FunctionCallbackInfo<Value>& args) {
315 Environment* env = Environment::GetCurrent(args);
316 Isolate* isolate = env->isolate();
317
318 const int argc = args.Length();
319 CHECK_GE(argc, 3)do { if (__builtin_expect(!!(!((argc) >= (3))), 0)) { do {
static const node::AssertionInfo args = { "../src/node_dir.cc"
":" "319", "(argc) >= (3)", __PRETTY_FUNCTION__ }; node::
Assert(args); } while (0); } } while (0)
;
1
Assuming 'argc' is >= 3
2
Taking false branch
3
Loop condition is false. Exiting loop
320
321 BufferValue path(isolate, args[0]);
322 CHECK_NOT_NULL(*path)do { if (__builtin_expect(!!(!((*path) != nullptr)), 0)) { do
{ static const node::AssertionInfo args = { "../src/node_dir.cc"
":" "322", "(*path) != nullptr", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
;
4
Assuming the condition is true
5
Taking false branch
6
Loop condition is false. Exiting loop
323
324 const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
325
326 FSReqBase* req_wrap_async = GetReqWrap(args, 2);
327 if (req_wrap_async != nullptr) { // openDir(path, encoding, req)
7
Assuming the condition is false
8
Taking false branch
328 AsyncCall(env, req_wrap_async, args, "opendir", encoding, AfterOpenDir,
329 uv_fs_opendir, *path);
330 } else { // openDir(path, encoding, undefined, ctx)
331 CHECK_EQ(argc, 4)do { if (__builtin_expect(!!(!((argc) == (4))), 0)) { do { static
const node::AssertionInfo args = { "../src/node_dir.cc" ":" "331"
, "(argc) == (4)", __PRETTY_FUNCTION__ }; node::Assert(args);
} while (0); } } while (0)
;
9
Assuming 'argc' is equal to 4
10
Taking false branch
11
Loop condition is false. Exiting loop
332 FSReqWrapSync req_wrap_sync;
333 FS_DIR_SYNC_TRACE_BEGIN(opendir)if ((*node::tracing::TraceEventHelper::GetCategoryGroupEnabled
("node" "," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync"
) != 0)) do { static std::atomic<intptr_t> trace_event_unique_atomic333
{0}; const uint8_t* trace_event_unique_category_group_enabled333
; trace_event_unique_category_group_enabled333 = reinterpret_cast
<const uint8_t*>((trace_event_unique_atomic333).load())
; if (!trace_event_unique_category_group_enabled333) { trace_event_unique_category_group_enabled333
= node::tracing::TraceEventHelper::GetCategoryGroupEnabled("node"
"," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync");
(trace_event_unique_atomic333).store(reinterpret_cast<intptr_t
>( trace_event_unique_category_group_enabled333)); };; if (
*trace_event_unique_category_group_enabled333 & (kEnabledForRecording_CategoryGroupEnabledFlags
| kEnabledForEventCallback_CategoryGroupEnabledFlags)) { node
::tracing::AddTraceEvent( ('B'), trace_event_unique_category_group_enabled333
, "fs_dir.sync." "opendir", node::tracing::kGlobalScope, node
::tracing::kNoId, node::tracing::kNoId, (static_cast<unsigned
int>(0))); } } while (0);
;
12
Taking false branch
334 int result = SyncCall(env, args[3], &req_wrap_sync, "opendir",
335 uv_fs_opendir, *path);
336 FS_DIR_SYNC_TRACE_END(opendir)if ((*node::tracing::TraceEventHelper::GetCategoryGroupEnabled
("node" "," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync"
) != 0)) do { static std::atomic<intptr_t> trace_event_unique_atomic336
{0}; const uint8_t* trace_event_unique_category_group_enabled336
; trace_event_unique_category_group_enabled336 = reinterpret_cast
<const uint8_t*>((trace_event_unique_atomic336).load())
; if (!trace_event_unique_category_group_enabled336) { trace_event_unique_category_group_enabled336
= node::tracing::TraceEventHelper::GetCategoryGroupEnabled("node"
"," "node" "." "fs_dir" "," "node" "." "fs_dir" "." "sync");
(trace_event_unique_atomic336).store(reinterpret_cast<intptr_t
>( trace_event_unique_category_group_enabled336)); };; if (
*trace_event_unique_category_group_enabled336 & (kEnabledForRecording_CategoryGroupEnabledFlags
| kEnabledForEventCallback_CategoryGroupEnabledFlags)) { node
::tracing::AddTraceEvent( ('E'), trace_event_unique_category_group_enabled336
, "fs_dir.sync." "opendir", node::tracing::kGlobalScope, node
::tracing::kNoId, node::tracing::kNoId, (static_cast<unsigned
int>(0))); } } while (0);
;
13
Taking false branch
337 if (result
13.1
'result' is >= 0
< 0) {
14
Taking false branch
338 return; // syscall failed, no need to continue, error info is in ctx
339 }
340
341 uv_fs_t* req = &req_wrap_sync.req;
342 uv_dir_t* dir = static_cast<uv_dir_t*>(req->ptr);
343 DirHandle* handle = DirHandle::New(env, dir);
15
Calling 'DirHandle::New'
18
Returned allocated memory
344
345 args.GetReturnValue().Set(handle->object().As<Value>());
19
Potential leak of memory pointed to by 'handle'
346 }
347}
348
349void Initialize(Local<Object> target,
350 Local<Value> unused,
351 Local<Context> context,
352 void* priv) {
353 Environment* env = Environment::GetCurrent(context);
354
355 env->SetMethod(target, "opendir", OpenDir);
356
357 // Create FunctionTemplate for DirHandle
358 Local<FunctionTemplate> dir = env->NewFunctionTemplate(DirHandle::New);
359 dir->Inherit(AsyncWrap::GetConstructorTemplate(env));
360 env->SetProtoMethod(dir, "read", DirHandle::Read);
361 env->SetProtoMethod(dir, "close", DirHandle::Close);
362 Local<ObjectTemplate> dirt = dir->InstanceTemplate();
363 dirt->SetInternalFieldCount(DirHandle::kInternalFieldCount);
364 env->SetConstructorFunction(target, "DirHandle", dir);
365 env->set_dir_instance_template(dirt);
366}
367
368void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
369 registry->Register(OpenDir);
370 registry->Register(DirHandle::New);
371 registry->Register(DirHandle::Read);
372 registry->Register(DirHandle::Close);
373}
374
375} // namespace fs_dir
376
377} // end namespace node
378
379NODE_MODULE_CONTEXT_AWARE_INTERNAL(fs_dir, node::fs_dir::Initialize)static node::node_module _module = { 108, NM_F_INTERNAL, nullptr
, "../src/node_dir.cc", nullptr, (node::addon_context_register_func
)(node::fs_dir::Initialize), "fs_dir", nullptr, nullptr}; void
_register_fs_dir() { node_module_register(&_module); }
380NODE_MODULE_EXTERNAL_REFERENCE(fs_dir, node::fs_dir::RegisterExternalReferences)void _register_external_reference_fs_dir( node::ExternalReferenceRegistry
* registry) { node::fs_dir::RegisterExternalReferences(registry
); }