Skip to content

Commit c43ebc8

Browse files
committed
crypto: avoid TLSWrap callbacks during GC
TLSWrap destructors can run from V8 weak callbacks. Avoid invoking queued write callbacks from that path because StreamReq::Done mutates JS-visible objects and may allocate on the V8 heap during weak callback processing. Refs: #62393 Made-with: Cursor
1 parent 34adeeb commit c43ebc8

2 files changed

Lines changed: 15 additions & 7 deletions

File tree

src/crypto/crypto_tls.cc

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,9 @@ TLSWrap::TLSWrap(Environment* env,
438438
}
439439

440440
TLSWrap::~TLSWrap() {
441-
Destroy();
441+
// Destructors can run from V8 weak callbacks during garbage collection.
442+
// Do not invoke JS-visible write callbacks from here.
443+
Destroy(false);
442444
}
443445

444446
MaybeLocal<ArrayBufferView> TLSWrap::ocsp_response() const {
@@ -1307,15 +1309,21 @@ void TLSWrap::DestroySSL(const FunctionCallbackInfo<Value>& args) {
13071309
Debug(wrap, "DestroySSL() finished");
13081310
}
13091311

1310-
void TLSWrap::Destroy() {
1312+
void TLSWrap::Destroy(bool invoke_queued) {
13111313
if (!ssl_)
13121314
return;
13131315

1314-
// If there is a write happening, mark it as finished.
1315-
write_callback_scheduled_ = true;
1316+
if (invoke_queued) {
1317+
// If there is a write happening, mark it as finished.
1318+
write_callback_scheduled_ = true;
13161319

1317-
// And destroy
1318-
InvokeQueued(UV_ECANCELED, "Canceled because of SSL destruction");
1320+
// And destroy
1321+
InvokeQueued(UV_ECANCELED, "Canceled because of SSL destruction");
1322+
} else {
1323+
current_write_.reset();
1324+
current_empty_write_.reset();
1325+
write_callback_scheduled_ = false;
1326+
}
13191327

13201328
env()->external_memory_accounter()->Decrease(env()->isolate(), kExternalSize);
13211329
ssl_.reset();

src/crypto/crypto_tls.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ class TLSWrap : public AsyncWrap,
159159
void EncOut(); // Write encrypted data from enc_out_ to underlying stream.
160160
void ClearIn(); // SSL_write() clear data "in" to SSL.
161161
void ClearOut(); // SSL_read() clear text "out" from SSL.
162-
void Destroy();
162+
void Destroy(bool invoke_queued = true);
163163

164164
// Call Done() on outstanding WriteWrap request.
165165
void InvokeQueued(int status, const char* error_str = nullptr);

0 commit comments

Comments
 (0)