1
+ #include " async_wrap.h"
1
2
#include " env-inl.h"
2
3
#include " node.h"
3
4
#include " node_errors.h"
@@ -16,18 +17,54 @@ using v8::Context;
16
17
using v8::Function;
17
18
using v8::FunctionCallbackInfo;
18
19
using v8::Isolate;
20
+ using v8::Just;
19
21
using v8::kPromiseHandlerAddedAfterReject ;
20
22
using v8::kPromiseRejectAfterResolved ;
21
23
using v8::kPromiseRejectWithNoHandler ;
22
24
using v8::kPromiseResolveAfterResolved ;
23
25
using v8::Local;
26
+ using v8::Maybe;
24
27
using v8::Number;
25
28
using v8::Object;
26
29
using v8::Promise;
27
30
using v8::PromiseRejectEvent;
28
31
using v8::PromiseRejectMessage;
29
32
using v8::Value;
30
33
34
+ static Maybe<double > GetAssignedPromiseAsyncId (Environment* env,
35
+ Local<Promise> promise,
36
+ Local<Value> id_symbol) {
37
+ Local<Value> maybe_async_id;
38
+ if (!promise->Get (env->context (), id_symbol).ToLocal (&maybe_async_id)) {
39
+ return v8::Just (AsyncWrap::kInvalidAsyncId );
40
+ }
41
+ return maybe_async_id->IsNumber ()
42
+ ? maybe_async_id->NumberValue (env->context ())
43
+ : v8::Just (AsyncWrap::kInvalidAsyncId );
44
+ }
45
+
46
+ static Maybe<double > GetAssignedPromiseWrapAsyncId (Environment* env,
47
+ Local<Promise> promise,
48
+ Local<Value> id_symbol) {
49
+ // This check is imperfect. If the internal field is set, it should
50
+ // be an object. If it's not, we just ignore it. Ideally v8 would
51
+ // have had GetInternalField returning a MaybeLocal but this works
52
+ // for now.
53
+ Local<Value> promiseWrap = promise->GetInternalField (0 );
54
+ if (promiseWrap->IsObject ()) {
55
+ Local<Value> maybe_async_id;
56
+ if (!promiseWrap.As <Object>()->Get (env->context (), id_symbol)
57
+ .ToLocal (&maybe_async_id)) {
58
+ return v8::Just (AsyncWrap::kInvalidAsyncId );
59
+ }
60
+ return maybe_async_id->IsNumber ()
61
+ ? maybe_async_id->NumberValue (env->context ())
62
+ : v8::Just (AsyncWrap::kInvalidAsyncId );
63
+ } else {
64
+ return v8::Just (AsyncWrap::kInvalidAsyncId );
65
+ }
66
+ }
67
+
31
68
void PromiseRejectCallback (PromiseRejectMessage message) {
32
69
static std::atomic<uint64_t > unhandledRejections{0 };
33
70
static std::atomic<uint64_t > rejectionsHandledAfter{0 };
@@ -76,12 +113,46 @@ void PromiseRejectCallback(PromiseRejectMessage message) {
76
113
77
114
Local<Value> args[] = { type, promise, value };
78
115
79
- // V8 does not expect this callback to have a scheduled exceptions once it
80
- // returns, so we print them out in a best effort to do something about it
81
- // without failing silently and without crashing the process.
116
+ double async_id = AsyncWrap::kInvalidAsyncId ;
117
+ double trigger_async_id = AsyncWrap::kInvalidAsyncId ;
82
118
TryCatchScope try_catch (env);
119
+
120
+ if (!GetAssignedPromiseAsyncId (env, promise, env->async_id_symbol ())
121
+ .To (&async_id)) return ;
122
+ if (!GetAssignedPromiseAsyncId (env, promise, env->trigger_async_id_symbol ())
123
+ .To (&trigger_async_id)) return ;
124
+
125
+ if (async_id == AsyncWrap::kInvalidAsyncId &&
126
+ trigger_async_id == AsyncWrap::kInvalidAsyncId ) {
127
+ // That means that promise might be a PromiseWrap, so we'll
128
+ // check there as well.
129
+ if (!GetAssignedPromiseWrapAsyncId (env, promise, env->async_id_symbol ())
130
+ .To (&async_id)) return ;
131
+ if (!GetAssignedPromiseWrapAsyncId (
132
+ env, promise, env->trigger_async_id_symbol ())
133
+ .To (&trigger_async_id)) return ;
134
+ }
135
+
136
+ if (async_id != AsyncWrap::kInvalidAsyncId &&
137
+ trigger_async_id != AsyncWrap::kInvalidAsyncId ) {
138
+ env->async_hooks ()->push_async_context (
139
+ async_id, trigger_async_id, promise);
140
+ }
141
+
83
142
USE (callback->Call (
84
143
env->context (), Undefined (isolate), arraysize (args), args));
144
+
145
+ if (async_id != AsyncWrap::kInvalidAsyncId &&
146
+ trigger_async_id != AsyncWrap::kInvalidAsyncId &&
147
+ env->execution_async_id () == async_id) {
148
+ // This condition might not be true if async_hooks was enabled during
149
+ // the promise callback execution.
150
+ env->async_hooks ()->pop_async_context (async_id);
151
+ }
152
+
153
+ // V8 does not expect this callback to have a scheduled exceptions once it
154
+ // returns, so we print them out in a best effort to do something about it
155
+ // without failing silently and without crashing the process.
85
156
if (try_catch.HasCaught () && !try_catch.HasTerminated ()) {
86
157
fprintf (stderr, " Exception in PromiseRejectCallback:\n " );
87
158
PrintCaughtException (isolate, env->context (), try_catch);
0 commit comments