Skip to content

Commit

Permalink
src: add PrintLibuvHandleInformation debug helper
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
addaleax committed Feb 6, 2019
1 parent 30a4e89 commit 7035496
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 13 deletions.
36 changes: 24 additions & 12 deletions src/debug_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -282,20 +282,36 @@ void DumpBacktrace(FILE* fp) {
void CheckedUvLoopClose(uv_loop_t* loop) {
if (uv_loop_close(loop) == 0) return;

auto sym_ctx = NativeSymbolDebuggingContext::New();
PrintLibuvHandleInformation(loop, stderr);

fflush(stderr);
// Finally, abort.
CHECK(0 && "uv_loop_close() while having open handles");
}

fprintf(stderr, "uv loop at [%p] has active handles\n", loop);
void PrintLibuvHandleInformation(uv_loop_t* loop, FILE* stream) {
struct Info {
std::unique_ptr<NativeSymbolDebuggingContext> 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<NativeSymbolDebuggingContext*>(arg);
Info* info = static_cast<Info*>(arg);
NativeSymbolDebuggingContext* sym_ctx = info->ctx.get();
FILE* stream = info->stream;

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<void*>(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`
Expand All @@ -309,14 +325,10 @@ void CheckedUvLoopClose(uv_loop_t* loop) {
first_field = *reinterpret_cast<void**>(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");
}, &info);
}

std::vector<std::string> NativeSymbolDebuggingContext::GetLoadedLibraries() {
Expand Down
1 change: 1 addition & 0 deletions src/debug_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion test/abort/test-addon-uv-handle-leak.js
Original file line number Diff line number Diff line change
Expand Up @@ -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':
Expand Down

0 comments on commit 7035496

Please sign in to comment.