Skip to content

Commit 79b11ce

Browse files
committed
async_wrap: print msg on error instead of abort
Print an error message when the stack is corrupted by the user. Use DumpBacktrace() to show where in the native stack the error occurred. Since it's likely that there will be no stack when this check is hit.
1 parent 90f0a63 commit 79b11ce

File tree

4 files changed

+28
-2
lines changed

4 files changed

+28
-2
lines changed

lib/async_hooks.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ const { kInit, kBefore, kAfter, kDestroy, kActiveHooks, kIdStackIndex,
5454
async_wrap.setupHooks({ init,
5555
before: emitBeforeN,
5656
after: emitAfterN,
57-
destroy: emitDestroyFromNative });
57+
destroy: emitDestroyFromNative,
58+
fatalError });
5859

5960
// Used to fatally abort the process if a callback throws.
6061
function fatalError(e) {

src/async-wrap.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,16 +138,21 @@ static void SetupHooks(const FunctionCallbackInfo<Value>& args) {
138138
Local<Value> destroy_v = fn_obj->Get(
139139
env->context(),
140140
FIXED_ONE_BYTE_STRING(env->isolate(), "destroy")).ToLocalChecked();
141+
Local<Value> fatal_error_v = fn_obj->Get(
142+
env->context(),
143+
FIXED_ONE_BYTE_STRING(env->isolate(), "fatalError")).ToLocalChecked();
141144

142145
CHECK(init_v->IsFunction());
143146
CHECK(before_v->IsFunction());
144147
CHECK(after_v->IsFunction());
145148
CHECK(destroy_v->IsFunction());
149+
CHECK(fatal_error_v->IsFunction());
146150

147151
env->set_async_hooks_init_function(init_v.As<Function>());
148152
env->set_async_hooks_before_function(before_v.As<Function>());
149153
env->set_async_hooks_after_function(after_v.As<Function>());
150154
env->set_async_hooks_destroy_function(destroy_v.As<Function>());
155+
env->set_async_hooks_fatal_error_function(fatal_error_v.As<Function>());
151156
}
152157

153158

src/env-inl.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,26 @@ inline void Environment::AsyncHooks::pop_from_id_stack(double id) {
147147
}
148148

149149
// Make sure the stack hasn't become corrupted.
150-
CHECK_EQ(id_stack_[fields_[AsyncHooks::kIdStackIndex]], id);
150+
if (id_stack_[fields_[AsyncHooks::kIdStackIndex]] != id) {
151+
DumpBacktrace(stderr);
152+
fprintf(stderr, "\n");
153+
fflush(stderr);
154+
// message + 2 * max number length) + 1
155+
char msg[77] = {};
156+
snprintf(msg,
157+
77,
158+
"async hook stack has become corrupted: %'.f %'.f",
159+
id_stack_[fields_[AsyncHooks::kIdStackIndex]],
160+
id);
161+
Environment* env = Environment::GetCurrent(isolate_);
162+
v8::HandleScope handle_scope(isolate_);
163+
v8::Local<v8::Function> fn = env->async_hooks_fatal_error_function();
164+
v8::Local<v8::Value> argv =
165+
FIXED_ONE_BYTE_STRING(isolate_, msg);
166+
fn->Call(env->context(), v8::Undefined(isolate_), 1, &argv)
167+
.ToLocalChecked();
168+
CHECK(false && "UNREACHABLE");
169+
}
151170

152171
// Fast path where there's probably no extra stack.
153172
if (fields_[AsyncHooks::kIdStackSize] < AsyncHooks::kIdStackLimit) {

src/env.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ namespace node {
233233
V(async_hooks_destroy_function, v8::Function) \
234234
V(async_hooks_init_function, v8::Function) \
235235
V(async_hooks_before_function, v8::Function) \
236+
V(async_hooks_fatal_error_function, v8::Function) \
236237
V(async_hooks_after_function, v8::Function) \
237238
V(binding_cache_object, v8::Object) \
238239
V(buffer_constructor_function, v8::Function) \

0 commit comments

Comments
 (0)