5
5
#pragma once
6
6
7
7
#include < kj/async.h>
8
+ #include < kj/debug.h>
8
9
9
10
namespace workerd ::api {
10
11
@@ -211,14 +212,19 @@ class DeferredProxyCoroutine: public kj::_::PromiseNode,
211
212
212
213
// PromiseNode implementation
213
214
215
+ void setSelfPointer (kj::_::OwnPromiseNode* selfPtr) noexcept override {
216
+ this ->selfPtr = selfPtr;
217
+ }
218
+
214
219
void destroy () override {
215
220
// The promise returned by `inner.get_return_object()` is what actually owns this coroutine
216
221
// frame. We temporarily store that in `result` until our outer promise is fulfilled. So, to
217
222
// destroy ourselves, we must manually drop `result`.
218
223
//
219
- // On the other hand, if our outer promise has already been fulfilled, and `result` delivered to
220
- // wherever it is going, then someone else directly owns the coroutine now, not us, and it's
221
- // okay for this drop to be a no-op.
224
+ // On the other hand, if our outer promise has already been fulfilled, then `result` has already
225
+ // been delivered to wherever it is going, and someone else directly owns the coroutine now, not
226
+ // us. In this case, this `destroy()` override will have already been called (and it will have
227
+ // been a no-op), because our own OwnPromiseNode will have already been dropped in `get()`.
222
228
223
229
auto drop = kj::mv (result);
224
230
}
@@ -228,6 +234,13 @@ class DeferredProxyCoroutine: public kj::_::PromiseNode,
228
234
}
229
235
230
236
void get (kj::_::ExceptionOrValue& output) noexcept override {
237
+ // Make sure that the outer PromiseNode (`this` one) is destroyed before the inner PromiseNode.
238
+ // kj-async should already provide us this guarantee, but since incorrect destruction order
239
+ // would cause invalid memory access, we provide a stronger guarantee. Also see the comment for
240
+ // the `result` data member.
241
+ KJ_ASSERT (selfPtr != nullptr );
242
+ KJ_DEFER (*selfPtr = nullptr );
243
+
231
244
static_cast <decltype (result)&>(output) = kj::mv (result);
232
245
}
233
246
@@ -249,6 +262,16 @@ class DeferredProxyCoroutine: public kj::_::PromiseNode,
249
262
250
263
kj::_::ExceptionOr<DeferredProxy<T>> result;
251
264
// Stores the result for the outer promise.
265
+ //
266
+ // WARNING: This object owns `this` PromiseNode! If `result` is ever moved away, as is done in
267
+ // `get()`, we must arrange to make sure that no one ever tries to use `this` PromiseNode again.
268
+ // Stated another way, we must guarantee that the outer PromiseNode (for `DeferredProxy<T>`) is
269
+ // always destroyed before the inner PromiseNode (for `T`). kj-async always does this anyway, but
270
+ // we implement an additional safeguard by immediately destroying our own `OwnPromiseNode` (which
271
+ // we have access to via `setSelfPointer()`) when we move `result` away in `get()`.
272
+
273
+ kj::_::OwnPromiseNode* selfPtr = nullptr ;
274
+ // Used to drop ourselves in `get()` -- see comment for `result`.
252
275
253
276
bool deferredProxyingHasBegun = false ;
254
277
// Set to true when deferred proxying has begun -- that is, when the outer DeferredProxy<T>
0 commit comments