@@ -97,11 +97,11 @@ class Win32SymbolDebuggingContext final : public NativeSymbolDebuggingContext {
97
97
public:
98
98
Win32SymbolDebuggingContext () {
99
99
current_process_ = GetCurrentProcess ();
100
- USE (SymInitialize (process , nullptr , true ));
100
+ USE (SymInitialize (current_process_ , nullptr , true ));
101
101
}
102
102
103
103
~Win32SymbolDebuggingContext () {
104
- USE (SymCleanup (process ));
104
+ USE (SymCleanup (current_process_ ));
105
105
}
106
106
107
107
SymbolInfo LookupSymbol (void * address) override {
@@ -114,16 +114,16 @@ class Win32SymbolDebuggingContext final : public NativeSymbolDebuggingContext {
114
114
info->SizeOfStruct = sizeof (SYMBOL_INFO);
115
115
116
116
SymbolInfo ret;
117
- const bool have_info = SymFromAddr (process ,
117
+ const bool have_info = SymFromAddr (current_process_ ,
118
118
reinterpret_cast <DWORD64>(address),
119
119
nullptr ,
120
120
info);
121
121
if (have_info && strlen (info->Name ) == 0 ) {
122
122
if (UnDecorateSymbolName (info->Name ,
123
- demangled_ ,
124
- sizeof (demangled_ ),
123
+ demangled ,
124
+ sizeof (demangled ),
125
125
UNDNAME_COMPLETE)) {
126
- ret.name = demangled_ ;
126
+ ret.name = demangled ;
127
127
} else {
128
128
ret.name = info->Name ;
129
129
}
@@ -135,7 +135,7 @@ class Win32SymbolDebuggingContext final : public NativeSymbolDebuggingContext {
135
135
bool IsMapped (void * address) override {
136
136
MEMORY_BASIC_INFORMATION info;
137
137
138
- if (VirtualQuery (address, &info, sizeof (info)) != info)
138
+ if (VirtualQuery (address, &info, sizeof (info)) != sizeof ( info) )
139
139
return false ;
140
140
141
141
return info.State == MEM_COMMIT && info.Protect != 0 ;
@@ -149,6 +149,7 @@ class Win32SymbolDebuggingContext final : public NativeSymbolDebuggingContext {
149
149
HANDLE current_process_;
150
150
};
151
151
152
+ std::unique_ptr<NativeSymbolDebuggingContext>
152
153
NativeSymbolDebuggingContext::New () {
153
154
return std::unique_ptr<NativeSymbolDebuggingContext>(
154
155
new Win32SymbolDebuggingContext ());
@@ -177,4 +178,48 @@ void DumpBacktrace(FILE* fp) {
177
178
}
178
179
}
179
180
181
+ void CheckedUvLoopClose (uv_loop_t * loop) {
182
+ if (uv_loop_close (loop) == 0 ) return ;
183
+
184
+ auto sym_ctx = NativeSymbolDebuggingContext::New ();
185
+
186
+ fprintf (stderr, " uv loop at [%p] has active handles\n " , loop);
187
+
188
+ uv_walk (loop, [](uv_handle_t * handle, void * arg) {
189
+ auto sym_ctx = static_cast <NativeSymbolDebuggingContext*>(arg);
190
+
191
+ fprintf (stderr, " [%p] %s\n " , handle, uv_handle_type_name (handle->type ));
192
+
193
+ void * close_cb = reinterpret_cast <void *>(handle->close_cb );
194
+ fprintf (stderr, " \t Close callback: %p %s\n " ,
195
+ close_cb, sym_ctx->LookupSymbol (close_cb).Display ().c_str ());
196
+
197
+ fprintf (stderr, " \t Data: %p %s\n " ,
198
+ handle->data , sym_ctx->LookupSymbol (handle->data ).Display ().c_str ());
199
+
200
+ // We are also interested in the first field of what `handle->data`
201
+ // points to, because for C++ code that is usually the virtual table pointer
202
+ // and gives us information about the exact kind of object we're looking at.
203
+ void * first_field = nullptr ;
204
+ // `handle->data` might be any value, including `nullptr`, or something
205
+ // cast from a completely different type; therefore, check that it’s
206
+ // dereferencable first.
207
+ if (sym_ctx->IsMapped (handle->data ))
208
+ first_field = *reinterpret_cast <void **>(handle->data );
209
+
210
+ if (first_field != nullptr ) {
211
+ fprintf (stderr, " \t (First field): %p %s\n " ,
212
+ first_field, sym_ctx->LookupSymbol (first_field).Display ().c_str ());
213
+ }
214
+ }, sym_ctx.get ());
215
+
216
+ fflush (stderr);
217
+ // Finally, abort.
218
+ CHECK (0 && " uv_loop_close() while having open handles" );
219
+ }
220
+
180
221
} // namespace node
222
+
223
+ extern " C" void __DumpBacktrace (FILE* fp) {
224
+ node::DumpBacktrace (fp);
225
+ }
0 commit comments