Commit aae45ca8 authored by Seth Brenith's avatar Seth Brenith Committed by V8 LUCI CQ

Avoid leaking Promises when detaching debugger

When the debugger is active and a Promise begins executing,
Isolate::PushPromise adds a global handle for that Promise. If the
debugger is no longer attached when the Promise finishes executing, then
there is no corresponding call to PopPromise which would clean up the
global handle. To avoid leaking memory in that case, we should clean up
the Promise stack when detaching the debugger.

Bug: v8:12613
Change-Id: I47a2c37713b43b482e23e2457e96fba5f52623f4
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3448949Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Seth Brenith <seth.brenith@microsoft.com>
Cr-Commit-Position: refs/heads/main@{#79017}
parent 0d05f180
......@@ -440,6 +440,7 @@ void Debug::Unload() {
ClearStepping();
RemoveAllCoverageInfos();
ClearAllDebuggerHints();
ClearGlobalPromiseStack();
debug_delegate_ = nullptr;
}
......@@ -1990,6 +1991,11 @@ void Debug::FreeDebugInfoListNode(DebugInfoListNode* prev,
delete node;
}
void Debug::ClearGlobalPromiseStack() {
while (isolate_->PopPromise()) {
}
}
bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) {
RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
HandleScope scope(isolate_);
......
......@@ -475,6 +475,8 @@ class V8_EXPORT_PRIVATE Debug {
DebugInfoListNode** curr);
void FreeDebugInfoListNode(DebugInfoListNode* prev, DebugInfoListNode* node);
void ClearGlobalPromiseStack();
void SetTemporaryObjectTrackingDisabled(bool disabled);
bool GetTemporaryObjectTrackingDisabled() const;
......
......@@ -2599,14 +2599,15 @@ void Isolate::PushPromise(Handle<JSObject> promise) {
tltop->promise_on_stack_ = new PromiseOnStack(global_promise, prev);
}
void Isolate::PopPromise() {
bool Isolate::PopPromise() {
ThreadLocalTop* tltop = thread_local_top();
if (tltop->promise_on_stack_ == nullptr) return;
if (tltop->promise_on_stack_ == nullptr) return false;
PromiseOnStack* prev = tltop->promise_on_stack_->prev();
Handle<Object> global_promise = tltop->promise_on_stack_->promise();
delete tltop->promise_on_stack_;
tltop->promise_on_stack_ = prev;
global_handles()->Destroy(global_promise.location());
return true;
}
namespace {
......
......@@ -855,7 +855,7 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
// Push and pop a promise and the current try-catch handler.
void PushPromise(Handle<JSObject> promise);
void PopPromise();
bool PopPromise();
// Return the relevant Promise that a throw/rejection pertains to, based
// on the contents of the Promise stack
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment