diff --git a/libcef/renderer/v8_impl.cc b/libcef/renderer/v8_impl.cc index a0127b251..f10582d94 100644 --- a/libcef/renderer/v8_impl.cc +++ b/libcef/renderer/v8_impl.cc @@ -329,9 +329,7 @@ class V8TrackArrayBuffer : public CefTrackNode { } ~V8TrackArrayBuffer() { - if (buffer_ != nullptr) { - release_callback_->ReleaseBuffer(buffer_); - } + ReleaseBuffer(); isolate_->AdjustAmountOfExternalAllocatedMemory( -static_cast(sizeof(V8TrackArrayBuffer))); } @@ -340,6 +338,13 @@ class V8TrackArrayBuffer : public CefTrackNode { return release_callback_; } + void ReleaseBuffer() { + if (buffer_ && release_callback_) { + release_callback_->ReleaseBuffer(buffer_); + } + Detach(); + } + void Detach() { buffer_ = nullptr; } // Attach this track object to the specified V8 object. @@ -1410,7 +1415,18 @@ CefRefPtr CefV8Value::CreateArrayBuffer( // released when the V8 object is destroyed. V8TrackArrayBuffer* tracker = new V8TrackArrayBuffer(isolate, buffer, release_callback); - v8::Local ab = v8::ArrayBuffer::New(isolate, buffer, length); + + auto deleter = [](void* data, size_t length, void* deleter_data) { + auto* tracker = reinterpret_cast(deleter_data); + if (tracker) { + tracker->ReleaseBuffer(); + } + }; + + std::unique_ptr backing = + v8::ArrayBuffer::NewBackingStore(buffer, length, deleter, tracker); + v8::Local ab = + v8::ArrayBuffer::New(isolate, std::move(backing)); // Attach the tracker object. tracker->AttachTo(context, ab); diff --git a/tests/ceftests/v8_unittest.cc b/tests/ceftests/v8_unittest.cc index b46c33b50..03dd08c33 100644 --- a/tests/ceftests/v8_unittest.cc +++ b/tests/ceftests/v8_unittest.cc @@ -577,13 +577,18 @@ class V8RendererTest : public ClientAppRenderer::Delegate, ->GetArrayBufferReleaseCallback() .get()) == release_callback); + // |neuteredValue| buffer is explicitly freed by NeuterArrayBuffer(). + EXPECT_FALSE(neuteredReleaseBufferCalled); EXPECT_TRUE(neuteredValue->NeuterArrayBuffer()); + EXPECT_TRUE(neuteredReleaseBufferCalled); + + // |value| buffer is implicitly freed when the value goes out of scope. + EXPECT_FALSE(releaseBufferCalled); } // Exit the V8 context. EXPECT_TRUE(destructorCalled); EXPECT_TRUE(releaseBufferCalled); EXPECT_TRUE(neuteredDestructorCalled); - EXPECT_FALSE(neuteredReleaseBufferCalled); EXPECT_TRUE(context->Exit()); DestroyTest(); }