Skip to content

Commit 5667369

Browse files
indutnyrvagg
authored andcommitted
buffer: neuter external nullptr buffers
Neuter external `nullptr` buffers, otherwise their contents will be materialized on access, and the buffer instance will be internalized. This leads to a crash like this: v8::ArrayBuffer::Neuter Only externalized ArrayBuffers can be neutered Fix: #3619 PR-URL: #3624 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Trevor Norris <[email protected]>
1 parent 7d0b589 commit 5667369

File tree

4 files changed

+60
-0
lines changed

4 files changed

+60
-0
lines changed

src/node_buffer.cc

+5
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,11 @@ MaybeLocal<Object> New(Environment* env,
362362
}
363363

364364
Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), data, length);
365+
// `Neuter()`ing is required here to prevent materialization of the backing
366+
// store in v8. `nullptr` buffers are not writable, so this is semantically
367+
// correct.
368+
if (data == nullptr)
369+
ab->Neuter();
365370
Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
366371
Maybe<bool> mb =
367372
ui->SetPrototype(env->context(), env->buffer_prototype_object());
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#include <node.h>
2+
#include <node_buffer.h>
3+
#include <util.h>
4+
#include <v8.h>
5+
6+
static int alive;
7+
8+
static void FreeCallback(char* data, void* hint) {
9+
CHECK_EQ(data, nullptr);
10+
alive--;
11+
}
12+
13+
void Run(const v8::FunctionCallbackInfo<v8::Value>& args) {
14+
v8::Isolate* isolate = args.GetIsolate();
15+
alive++;
16+
17+
{
18+
v8::HandleScope scope(isolate);
19+
v8::Local<v8::Object> buf = node::Buffer::New(
20+
isolate,
21+
nullptr,
22+
0,
23+
FreeCallback,
24+
nullptr).ToLocalChecked();
25+
26+
char* data = node::Buffer::Data(buf);
27+
CHECK_EQ(data, nullptr);
28+
}
29+
30+
isolate->RequestGarbageCollectionForTesting(
31+
v8::Isolate::kFullGarbageCollection);
32+
33+
CHECK_EQ(alive, 0);
34+
}
35+
36+
void init(v8::Local<v8::Object> target) {
37+
NODE_SET_METHOD(target, "run", Run);
38+
}
39+
40+
NODE_MODULE(binding, init);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
'targets': [
3+
{
4+
'target_name': 'binding',
5+
'sources': [ 'binding.cc' ]
6+
}
7+
]
8+
}
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
'use strict';
2+
// Flags: --expose-gc
3+
4+
require('../../common');
5+
var binding = require('./build/Release/binding');
6+
7+
binding.run();

0 commit comments

Comments
 (0)