Skip to content

Commit 7035496

Browse files
committed
src: add PrintLibuvHandleInformation debug helper
This function is not only helpful for debugging crashes, but can also be used as an ad-hoc debugging statement. PR-URL: #25905 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 30a4e89 commit 7035496

File tree

3 files changed

+26
-13
lines changed

3 files changed

+26
-13
lines changed

src/debug_utils.cc

+24-12
Original file line numberDiff line numberDiff line change
@@ -282,20 +282,36 @@ void DumpBacktrace(FILE* fp) {
282282
void CheckedUvLoopClose(uv_loop_t* loop) {
283283
if (uv_loop_close(loop) == 0) return;
284284

285-
auto sym_ctx = NativeSymbolDebuggingContext::New();
285+
PrintLibuvHandleInformation(loop, stderr);
286+
287+
fflush(stderr);
288+
// Finally, abort.
289+
CHECK(0 && "uv_loop_close() while having open handles");
290+
}
286291

287-
fprintf(stderr, "uv loop at [%p] has active handles\n", loop);
292+
void PrintLibuvHandleInformation(uv_loop_t* loop, FILE* stream) {
293+
struct Info {
294+
std::unique_ptr<NativeSymbolDebuggingContext> ctx;
295+
FILE* stream;
296+
};
297+
298+
Info info { NativeSymbolDebuggingContext::New(), stream };
299+
300+
fprintf(stream, "uv loop at [%p] has %d active handles\n",
301+
loop, loop->active_handles);
288302

289303
uv_walk(loop, [](uv_handle_t* handle, void* arg) {
290-
auto sym_ctx = static_cast<NativeSymbolDebuggingContext*>(arg);
304+
Info* info = static_cast<Info*>(arg);
305+
NativeSymbolDebuggingContext* sym_ctx = info->ctx.get();
306+
FILE* stream = info->stream;
291307

292-
fprintf(stderr, "[%p] %s\n", handle, uv_handle_type_name(handle->type));
308+
fprintf(stream, "[%p] %s\n", handle, uv_handle_type_name(handle->type));
293309

294310
void* close_cb = reinterpret_cast<void*>(handle->close_cb);
295-
fprintf(stderr, "\tClose callback: %p %s\n",
311+
fprintf(stream, "\tClose callback: %p %s\n",
296312
close_cb, sym_ctx->LookupSymbol(close_cb).Display().c_str());
297313

298-
fprintf(stderr, "\tData: %p %s\n",
314+
fprintf(stream, "\tData: %p %s\n",
299315
handle->data, sym_ctx->LookupSymbol(handle->data).Display().c_str());
300316

301317
// We are also interested in the first field of what `handle->data`
@@ -309,14 +325,10 @@ void CheckedUvLoopClose(uv_loop_t* loop) {
309325
first_field = *reinterpret_cast<void**>(handle->data);
310326

311327
if (first_field != nullptr) {
312-
fprintf(stderr, "\t(First field): %p %s\n",
328+
fprintf(stream, "\t(First field): %p %s\n",
313329
first_field, sym_ctx->LookupSymbol(first_field).Display().c_str());
314330
}
315-
}, sym_ctx.get());
316-
317-
fflush(stderr);
318-
// Finally, abort.
319-
CHECK(0 && "uv_loop_close() while having open handles");
331+
}, &info);
320332
}
321333

322334
std::vector<std::string> NativeSymbolDebuggingContext::GetLoadedLibraries() {

src/debug_utils.h

+1
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ class NativeSymbolDebuggingContext {
119119
// about giving information on currently existing handles, if there are any,
120120
// but still aborts the process.
121121
void CheckedUvLoopClose(uv_loop_t* loop);
122+
void PrintLibuvHandleInformation(uv_loop_t* loop, FILE* stream);
122123

123124
} // namespace node
124125

test/abort/test-addon-uv-handle-leak.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ if (process.argv[2] === 'child') {
8989

9090
switch (state) {
9191
case 'initial':
92-
assert(/^uv loop at \[.+\] has active handles$/.test(line), line);
92+
assert(/^uv loop at \[.+\] has \d+ active handles$/.test(line), line);
9393
state = 'handle-start';
9494
break;
9595
case 'handle-start':

0 commit comments

Comments
 (0)