mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-02-18 13:10:42 +01:00
Fix potential use-after-free of V8TrackArrayBuffer (fixes issue #3074)
This commit is contained in:
parent
96404f1fd9
commit
91ecc85e93
@ -318,18 +318,14 @@ class V8TrackArrayBuffer : public CefTrackNode {
|
|||||||
public:
|
public:
|
||||||
explicit V8TrackArrayBuffer(
|
explicit V8TrackArrayBuffer(
|
||||||
v8::Isolate* isolate,
|
v8::Isolate* isolate,
|
||||||
void* buffer,
|
|
||||||
CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback)
|
CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback)
|
||||||
: isolate_(isolate),
|
: isolate_(isolate), release_callback_(release_callback) {
|
||||||
buffer_(buffer),
|
|
||||||
release_callback_(release_callback) {
|
|
||||||
DCHECK(isolate_);
|
DCHECK(isolate_);
|
||||||
isolate_->AdjustAmountOfExternalAllocatedMemory(
|
isolate_->AdjustAmountOfExternalAllocatedMemory(
|
||||||
static_cast<int>(sizeof(V8TrackArrayBuffer)));
|
static_cast<int>(sizeof(V8TrackArrayBuffer)));
|
||||||
}
|
}
|
||||||
|
|
||||||
~V8TrackArrayBuffer() {
|
~V8TrackArrayBuffer() {
|
||||||
ReleaseBuffer();
|
|
||||||
isolate_->AdjustAmountOfExternalAllocatedMemory(
|
isolate_->AdjustAmountOfExternalAllocatedMemory(
|
||||||
-static_cast<int>(sizeof(V8TrackArrayBuffer)));
|
-static_cast<int>(sizeof(V8TrackArrayBuffer)));
|
||||||
}
|
}
|
||||||
@ -338,15 +334,6 @@ class V8TrackArrayBuffer : public CefTrackNode {
|
|||||||
return release_callback_;
|
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.
|
// Attach this track object to the specified V8 object.
|
||||||
void AttachTo(v8::Local<v8::Context> context,
|
void AttachTo(v8::Local<v8::Context> context,
|
||||||
v8::Local<v8::ArrayBuffer> arrayBuffer) {
|
v8::Local<v8::ArrayBuffer> arrayBuffer) {
|
||||||
@ -367,7 +354,6 @@ class V8TrackArrayBuffer : public CefTrackNode {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
v8::Isolate* isolate_;
|
v8::Isolate* isolate_;
|
||||||
void* buffer_;
|
|
||||||
CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback_;
|
CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback_;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1414,17 +1400,22 @@ CefRefPtr<CefV8Value> CefV8Value::CreateArrayBuffer(
|
|||||||
// Create a tracker object that will cause the user data reference to be
|
// Create a tracker object that will cause the user data reference to be
|
||||||
// released when the V8 object is destroyed.
|
// released when the V8 object is destroyed.
|
||||||
V8TrackArrayBuffer* tracker =
|
V8TrackArrayBuffer* tracker =
|
||||||
new V8TrackArrayBuffer(isolate, buffer, release_callback);
|
new V8TrackArrayBuffer(isolate, release_callback);
|
||||||
|
|
||||||
|
if (release_callback)
|
||||||
|
release_callback->AddRef();
|
||||||
|
|
||||||
auto deleter = [](void* data, size_t length, void* deleter_data) {
|
auto deleter = [](void* data, size_t length, void* deleter_data) {
|
||||||
auto* tracker = reinterpret_cast<V8TrackArrayBuffer*>(deleter_data);
|
auto* release_callback =
|
||||||
if (tracker) {
|
reinterpret_cast<CefV8ArrayBufferReleaseCallback*>(deleter_data);
|
||||||
tracker->ReleaseBuffer();
|
if (release_callback) {
|
||||||
|
release_callback->ReleaseBuffer(data);
|
||||||
|
release_callback->Release();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<v8::BackingStore> backing =
|
std::unique_ptr<v8::BackingStore> backing = v8::ArrayBuffer::NewBackingStore(
|
||||||
v8::ArrayBuffer::NewBackingStore(buffer, length, deleter, tracker);
|
buffer, length, deleter, release_callback.get());
|
||||||
v8::Local<v8::ArrayBuffer> ab =
|
v8::Local<v8::ArrayBuffer> ab =
|
||||||
v8::ArrayBuffer::New(isolate, std::move(backing));
|
v8::ArrayBuffer::New(isolate, std::move(backing));
|
||||||
|
|
||||||
@ -2302,8 +2293,6 @@ bool CefV8ValueImpl::NeuterArrayBuffer() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
arr->Detach();
|
arr->Detach();
|
||||||
V8TrackArrayBuffer* tracker = V8TrackArrayBuffer::Unwrap(context, obj);
|
|
||||||
tracker->Detach();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -547,48 +547,32 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
|||||||
|
|
||||||
bool destructorCalled = false;
|
bool destructorCalled = false;
|
||||||
bool releaseBufferCalled = false;
|
bool releaseBufferCalled = false;
|
||||||
|
|
||||||
bool neuteredDestructorCalled = false;
|
|
||||||
bool neuteredReleaseBufferCalled = false;
|
|
||||||
// Enter the V8 context.
|
// Enter the V8 context.
|
||||||
EXPECT_TRUE(context->Enter());
|
EXPECT_TRUE(context->Enter());
|
||||||
{
|
{
|
||||||
int static_data[16];
|
int static_data[16];
|
||||||
CefRefPtr<CefV8Value> value;
|
|
||||||
CefRefPtr<TestArrayBufferReleaseCallback> release_callback =
|
CefRefPtr<TestArrayBufferReleaseCallback> release_callback =
|
||||||
new TestArrayBufferReleaseCallback(&destructorCalled,
|
new TestArrayBufferReleaseCallback(&destructorCalled,
|
||||||
&releaseBufferCalled);
|
&releaseBufferCalled);
|
||||||
|
CefRefPtr<CefV8Value> value = CefV8Value::CreateArrayBuffer(
|
||||||
CefRefPtr<CefV8Value> neuteredValue;
|
static_data, sizeof(static_data), release_callback);
|
||||||
CefRefPtr<TestArrayBufferReleaseCallback> neuteredReleaseCallback =
|
|
||||||
new TestArrayBufferReleaseCallback(&neuteredDestructorCalled,
|
|
||||||
&neuteredReleaseBufferCalled);
|
|
||||||
value = CefV8Value::CreateArrayBuffer(static_data, sizeof(static_data),
|
|
||||||
release_callback);
|
|
||||||
neuteredValue = CefV8Value::CreateArrayBuffer(
|
|
||||||
static_data, sizeof(static_data), neuteredReleaseCallback);
|
|
||||||
EXPECT_TRUE(value.get());
|
EXPECT_TRUE(value.get());
|
||||||
EXPECT_TRUE(value->IsArrayBuffer());
|
EXPECT_TRUE(value->IsArrayBuffer());
|
||||||
EXPECT_TRUE(value->IsObject());
|
EXPECT_TRUE(value->IsObject());
|
||||||
EXPECT_FALSE(value->HasValue(0));
|
EXPECT_FALSE(value->HasValue(0));
|
||||||
EXPECT_FALSE(destructorCalled);
|
|
||||||
EXPECT_TRUE(value->GetArrayBufferReleaseCallback().get() != nullptr);
|
EXPECT_TRUE(value->GetArrayBufferReleaseCallback().get() != nullptr);
|
||||||
EXPECT_TRUE(((TestArrayBufferReleaseCallback*)value
|
EXPECT_TRUE(((TestArrayBufferReleaseCallback*)value
|
||||||
->GetArrayBufferReleaseCallback()
|
->GetArrayBufferReleaseCallback()
|
||||||
.get()) == release_callback);
|
.get()) == release_callback);
|
||||||
|
|
||||||
// |neuteredValue| buffer is explicitly freed by NeuterArrayBuffer().
|
// |Value| buffer is explicitly freed by NeuterArrayBuffer().
|
||||||
EXPECT_FALSE(neuteredReleaseBufferCalled);
|
EXPECT_FALSE(destructorCalled);
|
||||||
EXPECT_TRUE(neuteredValue->NeuterArrayBuffer());
|
|
||||||
EXPECT_TRUE(neuteredReleaseBufferCalled);
|
|
||||||
|
|
||||||
// |value| buffer is implicitly freed when the value goes out of scope.
|
|
||||||
EXPECT_FALSE(releaseBufferCalled);
|
EXPECT_FALSE(releaseBufferCalled);
|
||||||
|
EXPECT_TRUE(value->NeuterArrayBuffer());
|
||||||
|
EXPECT_TRUE(releaseBufferCalled);
|
||||||
}
|
}
|
||||||
// Exit the V8 context.
|
// Exit the V8 context.
|
||||||
EXPECT_TRUE(destructorCalled);
|
EXPECT_TRUE(destructorCalled);
|
||||||
EXPECT_TRUE(releaseBufferCalled);
|
|
||||||
EXPECT_TRUE(neuteredDestructorCalled);
|
|
||||||
EXPECT_TRUE(context->Exit());
|
EXPECT_TRUE(context->Exit());
|
||||||
DestroyTest();
|
DestroyTest();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user