From bcc41275a0ddba2c123b8d69a9e1e3473daf752e Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sun, 3 Feb 2019 15:01:36 +0100 Subject: [PATCH 1/2] 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. --- src/debug_utils.cc | 23 ++++++++++++++--------- src/debug_utils.h | 1 + 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/debug_utils.cc b/src/debug_utils.cc index 6dac86f002b07d..ef21a7585abb04 100644 --- a/src/debug_utils.cc +++ b/src/debug_utils.cc @@ -282,20 +282,29 @@ void DumpBacktrace(FILE* fp) { void CheckedUvLoopClose(uv_loop_t* loop) { if (uv_loop_close(loop) == 0) return; + PrintLibuvHandleInformation(loop, stderr); + + fflush(stderr); + // Finally, abort. + CHECK(0 && "uv_loop_close() while having open handles"); +} + +void PrintLibuvHandleInformation(uv_loop_t* loop, FILE* stream) { auto sym_ctx = NativeSymbolDebuggingContext::New(); - fprintf(stderr, "uv loop at [%p] has active handles\n", loop); + fprintf(stream, "uv loop at [%p] has %d active handles\n", + loop, loop->active_handles); uv_walk(loop, [](uv_handle_t* handle, void* arg) { auto sym_ctx = static_cast(arg); - fprintf(stderr, "[%p] %s\n", handle, uv_handle_type_name(handle->type)); + fprintf(stream, "[%p] %s\n", handle, uv_handle_type_name(handle->type)); void* close_cb = reinterpret_cast(handle->close_cb); - fprintf(stderr, "\tClose callback: %p %s\n", + fprintf(stream, "\tClose callback: %p %s\n", close_cb, sym_ctx->LookupSymbol(close_cb).Display().c_str()); - fprintf(stderr, "\tData: %p %s\n", + fprintf(stream, "\tData: %p %s\n", handle->data, sym_ctx->LookupSymbol(handle->data).Display().c_str()); // We are also interested in the first field of what `handle->data` @@ -309,14 +318,10 @@ void CheckedUvLoopClose(uv_loop_t* loop) { first_field = *reinterpret_cast(handle->data); if (first_field != nullptr) { - fprintf(stderr, "\t(First field): %p %s\n", + fprintf(stream, "\t(First field): %p %s\n", first_field, sym_ctx->LookupSymbol(first_field).Display().c_str()); } }, sym_ctx.get()); - - fflush(stderr); - // Finally, abort. - CHECK(0 && "uv_loop_close() while having open handles"); } std::vector NativeSymbolDebuggingContext::GetLoadedLibraries() { diff --git a/src/debug_utils.h b/src/debug_utils.h index 7e8a23d3ae309e..05a9370e562f82 100644 --- a/src/debug_utils.h +++ b/src/debug_utils.h @@ -119,6 +119,7 @@ class NativeSymbolDebuggingContext { // about giving information on currently existing handles, if there are any, // but still aborts the process. void CheckedUvLoopClose(uv_loop_t* loop); +void PrintLibuvHandleInformation(uv_loop_t* loop, FILE* stream); } // namespace node From 82921fea79de88b2a540f37216d1be00612413a4 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sun, 3 Feb 2019 20:32:12 +0100 Subject: [PATCH 2/2] fixup! src: add PrintLibuvHandleInformation debug helper --- src/debug_utils.cc | 13 ++++++++++--- test/abort/test-addon-uv-handle-leak.js | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/debug_utils.cc b/src/debug_utils.cc index ef21a7585abb04..434c9853c02a2e 100644 --- a/src/debug_utils.cc +++ b/src/debug_utils.cc @@ -290,13 +290,20 @@ void CheckedUvLoopClose(uv_loop_t* loop) { } void PrintLibuvHandleInformation(uv_loop_t* loop, FILE* stream) { - auto sym_ctx = NativeSymbolDebuggingContext::New(); + struct Info { + std::unique_ptr ctx; + FILE* stream; + }; + + Info info { NativeSymbolDebuggingContext::New(), stream }; fprintf(stream, "uv loop at [%p] has %d active handles\n", loop, loop->active_handles); uv_walk(loop, [](uv_handle_t* handle, void* arg) { - auto sym_ctx = static_cast(arg); + Info* info = static_cast(arg); + NativeSymbolDebuggingContext* sym_ctx = info->ctx.get(); + FILE* stream = info->stream; fprintf(stream, "[%p] %s\n", handle, uv_handle_type_name(handle->type)); @@ -321,7 +328,7 @@ void PrintLibuvHandleInformation(uv_loop_t* loop, FILE* stream) { fprintf(stream, "\t(First field): %p %s\n", first_field, sym_ctx->LookupSymbol(first_field).Display().c_str()); } - }, sym_ctx.get()); + }, &info); } std::vector NativeSymbolDebuggingContext::GetLoadedLibraries() { diff --git a/test/abort/test-addon-uv-handle-leak.js b/test/abort/test-addon-uv-handle-leak.js index 58061b0532fb8a..0bfb6cdb94b72d 100644 --- a/test/abort/test-addon-uv-handle-leak.js +++ b/test/abort/test-addon-uv-handle-leak.js @@ -89,7 +89,7 @@ if (process.argv[2] === 'child') { switch (state) { case 'initial': - assert(/^uv loop at \[.+\] has active handles$/.test(line), line); + assert(/^uv loop at \[.+\] has \d+ active handles$/.test(line), line); state = 'handle-start'; break; case 'handle-start':