mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
Enable V8 sandbox by default (fixes #3332)
When the V8 sandbox is enabled, ArrayBuffer backing stores must be allocated inside the sandbox address space. This change introduces a new CefV8Value::CreateArrayBufferWithCopy method that copies the memory contents into the sandbox address space. Enabling the V8 sandbox can have a performance impact, especially when passing large ArrayBuffers from C++ code to the JS side. We have therefore retained the old CefV8Value::CreateArrayBuffer method that references external memory. However, this method can only be used if the V8 sandbox is disabled at CEF/Chromium build time. To disable the V8 sandbox add `v8_enable_sandbox=false` to `GN_DEFINES` when building CEF/Chromium.
This commit is contained in:
committed by
Marshall Greenblatt
parent
08ae3a44a6
commit
295ea1f715
@@ -322,6 +322,7 @@ PERF_TEST_FUNC(V8ObjectGetValueWithAccessor) {
|
||||
PERF_ITERATIONS_END()
|
||||
}
|
||||
|
||||
#ifndef CEF_V8_ENABLE_SANDBOX
|
||||
PERF_TEST_FUNC(V8ArrayBufferCreate) {
|
||||
class ReleaseCallback : public CefV8ArrayBufferReleaseCallback {
|
||||
public:
|
||||
@@ -339,6 +340,17 @@ PERF_TEST_FUNC(V8ArrayBufferCreate) {
|
||||
CefV8Value::CreateArrayBuffer(buffer, byte_len, callback);
|
||||
PERF_ITERATIONS_END()
|
||||
}
|
||||
#endif // CEF_V8_ENABLE_SANDBOX
|
||||
|
||||
PERF_TEST_FUNC(V8ArrayBufferCopy) {
|
||||
constexpr size_t len = 1;
|
||||
constexpr size_t byte_len = len * sizeof(float);
|
||||
std::array<float, len> buffer = {0};
|
||||
PERF_ITERATIONS_START()
|
||||
CefRefPtr<CefV8Value> ret =
|
||||
CefV8Value::CreateArrayBufferWithCopy(buffer.data(), byte_len);
|
||||
PERF_ITERATIONS_END()
|
||||
}
|
||||
|
||||
PERF_TEST_FUNC(V8ContextEnterExit) {
|
||||
CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
|
||||
@@ -385,7 +397,10 @@ const PerfTestEntry kPerfTests[] = {
|
||||
PERF_TEST_ENTRY(V8ObjectGetValue),
|
||||
PERF_TEST_ENTRY(V8ObjectSetValueWithAccessor),
|
||||
PERF_TEST_ENTRY(V8ObjectGetValueWithAccessor),
|
||||
#ifndef CEF_V8_ENABLE_SANDBOX
|
||||
PERF_TEST_ENTRY(V8ArrayBufferCreate),
|
||||
#endif // CEF_V8_ENABLE_SANDBOX
|
||||
PERF_TEST_ENTRY(V8ArrayBufferCopy),
|
||||
PERF_TEST_ENTRY(V8ContextEnterExit),
|
||||
PERF_TEST_ENTRY(V8ContextEval),
|
||||
};
|
||||
|
@@ -3,11 +3,12 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Binary vs String Transfer Benchmark</title>
|
||||
<script src="https://cdn.plot.ly/plotly-2.26.0.min.js"></script>
|
||||
<script src="https://cdn.plot.ly/plotly-2.34.0.min.js"></script>
|
||||
<style>
|
||||
body {
|
||||
font-family: Tahoma, Serif;
|
||||
font-size: 10pt;
|
||||
background-color: white;
|
||||
}
|
||||
.info {
|
||||
font-size: 12pt;
|
||||
@@ -116,7 +117,9 @@
|
||||
<div id="round_trip_avg_chart">
|
||||
<!-- Average round trip linear chart will be drawn inside this DIV -->
|
||||
</div>
|
||||
|
||||
<div id="round_trip_chart">
|
||||
<!-- Round trip linear chart will be drawn inside this DIV -->
|
||||
</div>
|
||||
<div id="box_plot_chart">
|
||||
<!-- Box plot of round trip time will be drawn inside this DIV -->
|
||||
</div>
|
||||
@@ -125,13 +128,14 @@
|
||||
let tests = [];
|
||||
let box_plot_test_data = [];
|
||||
let round_trip_avg_plot_data = [];
|
||||
let round_trip_plot_data = [];
|
||||
|
||||
function nextTestSuite(testIndex) {
|
||||
const nextTestIndex = testIndex + 1;
|
||||
setTimeout(execTestSuite, 0, nextTestIndex);
|
||||
}
|
||||
|
||||
function generateRandomString(size) {
|
||||
function generateString(size) {
|
||||
// Symbols that will be encoded as two bytes in UTF-8
|
||||
// so we compare transfer of the same amount of bytes
|
||||
const characters =
|
||||
@@ -144,7 +148,7 @@
|
||||
return randomString;
|
||||
}
|
||||
|
||||
function generateRandomArrayBuffer(size) {
|
||||
function generateArrayBuffer(size) {
|
||||
const buffer = new ArrayBuffer(size);
|
||||
const uint8Array = new Uint8Array(buffer);
|
||||
for (let i = 0; i < uint8Array.length; i++) {
|
||||
@@ -157,8 +161,7 @@
|
||||
console.error(`ErrorCode:${errorCode} Message:${errorMessage}`);
|
||||
}
|
||||
|
||||
function sendString(size, testIndex) {
|
||||
const request = generateRandomString(size);
|
||||
function sendString(request, testIndex) {
|
||||
const startTime = performance.now();
|
||||
const onSuccess = (response) => {
|
||||
const roundTrip = performance.now() - startTime;
|
||||
@@ -166,6 +169,8 @@
|
||||
test.totalRoundTrip += roundTrip;
|
||||
test.sample++;
|
||||
box_plot_test_data[testIndex].x.push(roundTrip);
|
||||
round_trip_plot_data[testIndex].x.push(test.sample);
|
||||
round_trip_plot_data[testIndex].y.push(roundTrip);
|
||||
setTimeout(execTest, 0, testIndex);
|
||||
};
|
||||
|
||||
@@ -176,8 +181,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
function sendArrayBuffer(size, testIndex) {
|
||||
const request = generateRandomArrayBuffer(size);
|
||||
function sendArrayBuffer(request, testIndex) {
|
||||
const startTime = performance.now();
|
||||
const onSuccess = (response) => {
|
||||
const roundTrip = performance.now() - startTime;
|
||||
@@ -185,6 +189,8 @@
|
||||
test.totalRoundTrip += roundTrip;
|
||||
test.sample++;
|
||||
box_plot_test_data[testIndex].x.push(roundTrip);
|
||||
round_trip_plot_data[testIndex].x.push(test.sample);
|
||||
round_trip_plot_data[testIndex].y.push(roundTrip);
|
||||
setTimeout(execTest, 0, testIndex);
|
||||
};
|
||||
|
||||
@@ -209,7 +215,7 @@
|
||||
if (test.sample >= test.totalSamples) {
|
||||
return nextTestSuite(testIndex);
|
||||
}
|
||||
test.func(test.length, test.index);
|
||||
test.func(test.request, test.index);
|
||||
}
|
||||
|
||||
function column(prepared, value) {
|
||||
@@ -279,14 +285,14 @@
|
||||
function buildTestResults(tests) {
|
||||
testResults = [];
|
||||
|
||||
let oldRoundTrip = {
|
||||
let stringRoundTrip = {
|
||||
x: [],
|
||||
y: [],
|
||||
type: "scatter",
|
||||
name: "String",
|
||||
};
|
||||
|
||||
let newRoundTrip = {
|
||||
let binaryRoundTrip = {
|
||||
x: [],
|
||||
y: [],
|
||||
type: "scatter",
|
||||
@@ -332,13 +338,13 @@
|
||||
stdDeviationBinary: stdDeviationBinary,
|
||||
});
|
||||
|
||||
oldRoundTrip.x.push(test.byteSize);
|
||||
newRoundTrip.x.push(test.byteSize);
|
||||
oldRoundTrip.y.push(avgRoundTrip);
|
||||
newRoundTrip.y.push(avgRoundTripBin);
|
||||
stringRoundTrip.x.push(test.byteSize);
|
||||
binaryRoundTrip.x.push(test.byteSize);
|
||||
stringRoundTrip.y.push(avgRoundTrip);
|
||||
binaryRoundTrip.y.push(avgRoundTripBin);
|
||||
}
|
||||
|
||||
round_trip_avg_plot_data = [oldRoundTrip, newRoundTrip];
|
||||
round_trip_avg_plot_data = [stringRoundTrip, binaryRoundTrip];
|
||||
return testResults;
|
||||
}
|
||||
|
||||
@@ -374,17 +380,21 @@
|
||||
box_plot_test_data.forEach((data) => {
|
||||
data.x = [];
|
||||
});
|
||||
round_trip_plot_data.forEach((data) => {
|
||||
data.x = [];
|
||||
data.y = [];
|
||||
});
|
||||
}
|
||||
|
||||
function queueTest(name, byteSize, length, testFunc) {
|
||||
function queueTest(name, byteSize, request, testFunc) {
|
||||
const testIndex = tests.length;
|
||||
test = {
|
||||
name: name,
|
||||
byteSize: byteSize,
|
||||
length: length,
|
||||
index: testIndex,
|
||||
sample: 0,
|
||||
totalRoundTrip: 0,
|
||||
request: request,
|
||||
func: testFunc,
|
||||
};
|
||||
tests.push(test);
|
||||
@@ -397,11 +407,18 @@
|
||||
jitter: 0.3,
|
||||
pointpos: -1.8,
|
||||
});
|
||||
|
||||
round_trip_plot_data.push({
|
||||
x: [],
|
||||
y: [],
|
||||
type: "scatter",
|
||||
name: name,
|
||||
});
|
||||
}
|
||||
|
||||
function execTestSuite(testIndex) {
|
||||
if (testIndex < tests.length) {
|
||||
execTest(testIndex);
|
||||
setTimeout(execTest, 0, testIndex);
|
||||
} else {
|
||||
testsRunFinished();
|
||||
}
|
||||
@@ -426,19 +443,16 @@
|
||||
testResults = buildTestResults(tests);
|
||||
testResults.forEach((result) => displayResult(result));
|
||||
|
||||
const round_trip_layout = {
|
||||
Plotly.newPlot("round_trip_avg_chart", round_trip_avg_plot_data, {
|
||||
title: "Average round trip, μs (Smaller Better)",
|
||||
};
|
||||
Plotly.newPlot(
|
||||
"round_trip_avg_chart",
|
||||
round_trip_avg_plot_data,
|
||||
round_trip_layout
|
||||
);
|
||||
});
|
||||
Plotly.newPlot("round_trip_chart", round_trip_plot_data, {
|
||||
title: "Linear: Round Trip Time, μs",
|
||||
});
|
||||
Plotly.newPlot("box_plot_chart", box_plot_test_data, {
|
||||
title: "Box plot: Round Trip Time, μs",
|
||||
});
|
||||
|
||||
const box_plot_layout = {
|
||||
title: "Round Trip Time, μs",
|
||||
};
|
||||
Plotly.newPlot("box_plot_chart", box_plot_test_data, box_plot_layout);
|
||||
setSettingsState(false);
|
||||
}
|
||||
|
||||
@@ -466,6 +480,7 @@
|
||||
window.runTestSuite = () => {
|
||||
Plotly.purge("round_trip_avg_chart");
|
||||
Plotly.purge("box_plot_chart");
|
||||
Plotly.purge("round_trip_chart");
|
||||
setSettingsState(true);
|
||||
const totalSamples = parseInt(
|
||||
document.getElementById("sSamples").value
|
||||
@@ -474,21 +489,22 @@
|
||||
};
|
||||
|
||||
const totalSamples = parseInt(document.getElementById("sSamples").value);
|
||||
queueTest("Empty String", 0, 0, sendString);
|
||||
queueTest("Empty Binary", 0, 0, sendArrayBuffer);
|
||||
for (let byteSize = 8; byteSize <= 512 * 1024; byteSize *= 2) {
|
||||
|
||||
queueTest("Empty String", 0, generateString(0), sendString);
|
||||
queueTest("Empty Binary", 0, generateArrayBuffer(0), sendArrayBuffer);
|
||||
for (let byteSize = 8; byteSize <= 512 * 1024; byteSize *= 4) {
|
||||
// Byte size of a string is twice its length because of UTF-16 encoding
|
||||
const stringLen = byteSize / 2;
|
||||
queueTest(
|
||||
humanFileSize(byteSize) + " String",
|
||||
byteSize,
|
||||
stringLen,
|
||||
generateString(stringLen),
|
||||
sendString
|
||||
);
|
||||
queueTest(
|
||||
humanFileSize(byteSize) + " Binary",
|
||||
byteSize,
|
||||
byteSize,
|
||||
generateArrayBuffer(byteSize),
|
||||
sendArrayBuffer
|
||||
);
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@
|
||||
body {
|
||||
font-family: Tahoma, Serif;
|
||||
font-size: 10pt;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.left {
|
||||
|
@@ -58,9 +58,12 @@ enum V8TestMode {
|
||||
V8TEST_EMPTY_STRING_CREATE,
|
||||
V8TEST_ARRAY_CREATE,
|
||||
V8TEST_ARRAY_VALUE,
|
||||
#ifndef CEF_V8_ENABLE_SANDBOX
|
||||
V8TEST_ARRAY_BUFFER,
|
||||
V8TEST_ARRAY_BUFFER_CREATE_EMPTY,
|
||||
V8TEST_ARRAY_BUFFER_VALUE,
|
||||
#endif // CEF_V8_ENABLE_SANDBOX
|
||||
V8TEST_ARRAY_BUFFER_CREATE_EMPTY,
|
||||
V8TEST_ARRAY_BUFFER_COPY,
|
||||
V8TEST_OBJECT_CREATE,
|
||||
V8TEST_OBJECT_USERDATA,
|
||||
V8TEST_OBJECT_ACCESSOR,
|
||||
@@ -149,14 +152,19 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
||||
case V8TEST_ARRAY_VALUE:
|
||||
RunArrayValueTest();
|
||||
break;
|
||||
#ifndef CEF_V8_ENABLE_SANDBOX
|
||||
case V8TEST_ARRAY_BUFFER:
|
||||
RunArrayBufferTest();
|
||||
break;
|
||||
case V8TEST_ARRAY_BUFFER_VALUE:
|
||||
RunArrayBufferValueTest();
|
||||
break;
|
||||
#endif // CEF_V8_ENABLE_SANDBOX
|
||||
case V8TEST_ARRAY_BUFFER_CREATE_EMPTY:
|
||||
RunArrayBufferCreateEmptyTest();
|
||||
break;
|
||||
case V8TEST_ARRAY_BUFFER_VALUE:
|
||||
RunArrayBufferValueTest();
|
||||
case V8TEST_ARRAY_BUFFER_COPY:
|
||||
RunArrayBufferCopyTest();
|
||||
break;
|
||||
case V8TEST_OBJECT_CREATE:
|
||||
RunObjectCreateTest();
|
||||
@@ -612,6 +620,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
||||
DestroyTest();
|
||||
}
|
||||
|
||||
#ifndef CEF_V8_ENABLE_SANDBOX
|
||||
void RunArrayBufferTest() {
|
||||
class TestArrayBufferReleaseCallback
|
||||
: public CefV8ArrayBufferReleaseCallback {
|
||||
@@ -654,10 +663,11 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
||||
void* data = value->GetArrayBufferData();
|
||||
EXPECT_EQ(static_cast<int*>(data), static_data);
|
||||
EXPECT_FALSE(value->HasValue(0));
|
||||
EXPECT_TRUE(value->GetArrayBufferReleaseCallback().get() != nullptr);
|
||||
EXPECT_TRUE(((TestArrayBufferReleaseCallback*)value
|
||||
->GetArrayBufferReleaseCallback()
|
||||
.get()) == release_callback);
|
||||
EXPECT_NE(value->GetArrayBufferReleaseCallback().get(), nullptr);
|
||||
EXPECT_EQ((TestArrayBufferReleaseCallback*)value
|
||||
->GetArrayBufferReleaseCallback()
|
||||
.get(),
|
||||
release_callback);
|
||||
|
||||
// |Value| buffer is explicitly freed by NeuterArrayBuffer().
|
||||
EXPECT_FALSE(destructorCalled);
|
||||
@@ -670,7 +680,33 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
||||
EXPECT_TRUE(context->Exit());
|
||||
DestroyTest();
|
||||
}
|
||||
#endif // CEF_V8_ENABLE_SANDBOX
|
||||
|
||||
void RunArrayBufferCopyTest() {
|
||||
CefRefPtr<CefV8Context> context = GetContext();
|
||||
|
||||
// Enter the V8 context.
|
||||
EXPECT_TRUE(context->Enter());
|
||||
{
|
||||
int static_data[16] = {1, 2, 3, 4};
|
||||
CefRefPtr<CefV8Value> value = CefV8Value::CreateArrayBufferWithCopy(
|
||||
static_data, sizeof(static_data));
|
||||
EXPECT_TRUE(value.get());
|
||||
EXPECT_TRUE(value->IsArrayBuffer());
|
||||
EXPECT_TRUE(value->IsObject());
|
||||
EXPECT_EQ(value->GetArrayBufferByteLength(), sizeof(static_data));
|
||||
void* data = value->GetArrayBufferData();
|
||||
EXPECT_EQ(static_cast<int*>(data)[0], static_data[0]);
|
||||
EXPECT_EQ(static_cast<int*>(data)[1], static_data[1]);
|
||||
|
||||
EXPECT_FALSE(value->HasValue(0));
|
||||
}
|
||||
// Exit the V8 context.
|
||||
EXPECT_TRUE(context->Exit());
|
||||
DestroyTest();
|
||||
}
|
||||
|
||||
#ifndef CEF_V8_ENABLE_SANDBOX
|
||||
void RunArrayBufferValueTest() {
|
||||
class TestArrayBufferReleaseCallback
|
||||
: public CefV8ArrayBufferReleaseCallback {
|
||||
@@ -720,8 +756,17 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
||||
EXPECT_TRUE(context->Exit());
|
||||
DestroyTest();
|
||||
}
|
||||
#endif // CEF_V8_ENABLE_SANDBOX
|
||||
|
||||
void RunArrayBufferCreateEmptyTest() {
|
||||
// Enter the V8 context
|
||||
CefRefPtr<CefV8Context> context = GetContext();
|
||||
EXPECT_TRUE(context->Enter());
|
||||
|
||||
const size_t zero_size = 0;
|
||||
void* null_data = nullptr;
|
||||
CefRefPtr<CefV8Value> value;
|
||||
#ifndef CEF_V8_ENABLE_SANDBOX
|
||||
class TestArrayBufferReleaseCallback
|
||||
: public CefV8ArrayBufferReleaseCallback {
|
||||
public:
|
||||
@@ -733,22 +778,17 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
||||
CefRefPtr<TestArrayBufferReleaseCallback> owner =
|
||||
new TestArrayBufferReleaseCallback();
|
||||
|
||||
// Enter the V8 context
|
||||
CefRefPtr<CefV8Context> context = GetContext();
|
||||
EXPECT_TRUE(context->Enter());
|
||||
|
||||
const size_t zero_size = 0;
|
||||
void* null_data = nullptr;
|
||||
|
||||
CefRefPtr<CefV8Value> value =
|
||||
CefV8Value::CreateArrayBuffer(null_data, zero_size, owner);
|
||||
EXPECT_EQ(value->GetArrayBufferByteLength(), zero_size);
|
||||
value = CefV8Value::CreateArrayBuffer(null_data, zero_size, owner);
|
||||
EXPECT_EQ(value->GetArrayBufferData(), null_data);
|
||||
EXPECT_NE(value->GetArrayBufferReleaseCallback().get(), nullptr);
|
||||
#else
|
||||
value = CefV8Value::CreateArrayBufferWithCopy(null_data, zero_size);
|
||||
#endif
|
||||
EXPECT_EQ(value->GetArrayBufferByteLength(), zero_size);
|
||||
|
||||
CefRefPtr<CefV8Value> object = context->GetGlobal();
|
||||
EXPECT_TRUE(object.get());
|
||||
EXPECT_TRUE(object->SetValue("arr", value, V8_PROPERTY_ATTRIBUTE_NONE));
|
||||
EXPECT_NE(value->GetArrayBufferReleaseCallback().get(), nullptr);
|
||||
EXPECT_TRUE(value->NeuterArrayBuffer());
|
||||
|
||||
// Exit the V8 context.
|
||||
@@ -3413,9 +3453,12 @@ V8_TEST(StringCreate, V8TEST_STRING_CREATE)
|
||||
V8_TEST(EmptyStringCreate, V8TEST_EMPTY_STRING_CREATE)
|
||||
V8_TEST(ArrayCreate, V8TEST_ARRAY_CREATE)
|
||||
V8_TEST(ArrayValue, V8TEST_ARRAY_VALUE)
|
||||
#ifndef CEF_V8_ENABLE_SANDBOX
|
||||
V8_TEST(ArrayBuffer, V8TEST_ARRAY_BUFFER)
|
||||
V8_TEST(ArrayBufferCreateEmpty, V8TEST_ARRAY_BUFFER_CREATE_EMPTY)
|
||||
V8_TEST(ArrayBufferValue, V8TEST_ARRAY_BUFFER_VALUE)
|
||||
#endif // CEF_V8_ENABLE_SANDBOX
|
||||
V8_TEST(ArrayBufferCreateEmpty, V8TEST_ARRAY_BUFFER_CREATE_EMPTY)
|
||||
V8_TEST(ArrayBufferCopy, V8TEST_ARRAY_BUFFER_COPY)
|
||||
V8_TEST(ObjectCreate, V8TEST_OBJECT_CREATE)
|
||||
V8_TEST(ObjectUserData, V8TEST_OBJECT_USERDATA)
|
||||
V8_TEST(ObjectAccessor, V8TEST_OBJECT_ACCESSOR)
|
||||
|
Reference in New Issue
Block a user