Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

buffer: backport --zero-fill-buffers command line option #5744

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions doc/api/buffer.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,23 @@ for (var b of buf)
Additionally, the [`buf.values()`][], [`buf.keys()`][], and
[`buf.entries()`][] methods can be used to create iterators.

## The `--zero-fill-buffers` command line option

Node.js can be started using the `--zero-fill-buffers` command line option to
force all newly allocated `Buffer` and `SlowBuffer` instances created using
either `new Buffer(size)` and `new SlowBuffer(size)` to be *automatically
zero-filled* upon creation. Use of this flag *changes the default behavior* of
these methods and *can have a significant impact* on performance. Use of the
`--zero-fill-buffers` option is recommended only when absolutely necessary to
enforce that newly allocated `Buffer` instances cannot contain potentially
sensitive data.

```
$ node --zero-fill-buffers
> Buffer(5);
<Buffer 00 00 00 00 00>
```

## Class: Buffer

The Buffer class is a global type for dealing with binary data directly.
Expand Down
3 changes: 3 additions & 0 deletions doc/api/cli.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ instances.

Track heap object allocations for heap snapshots.

### `--zero-fill-buffers`

Automatically zero-fills all newly allocated Buffer and SlowBuffer instances.

### `--prof-process`

Expand Down
4 changes: 4 additions & 0 deletions doc/node.1
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ of the event loop.
.BR \-\-track\-heap-objects
Track heap object allocations for heap snapshots.

.TP
.BR \-\-zero\-fill\-buffers
Automatically zero-fills all newly allocated Buffer and SlowBuffer instances.

.TP
.BR \-\-prof\-process
Process v8 profiler output generated using the v8 option \fB\-\-prof\fR
Expand Down
8 changes: 7 additions & 1 deletion src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -946,7 +946,9 @@ Local<Value> WinapiErrnoException(Isolate* isolate,


void* ArrayBufferAllocator::Allocate(size_t size) {
if (env_ == nullptr || !env_->array_buffer_allocator_info()->no_zero_fill())
if (env_ == nullptr ||
!env_->array_buffer_allocator_info()->no_zero_fill() ||
zero_fill_all_buffers)
return calloc(size, 1);
env_->array_buffer_allocator_info()->reset_fill_flag();
return malloc(size);
Expand Down Expand Up @@ -3261,6 +3263,8 @@ static void PrintHelp() {
"snapshots\n"
" --prof-process process v8 profiler output generated\n"
" using --prof\n"
" --zero-fill-buffers automatically zero-fill all newly allocated\n"
" Buffer and SlowBuffer instances\n"
" --v8-options print v8 command line options\n"
#if HAVE_OPENSSL
" --tls-cipher-list=val use an alternative default TLS cipher list\n"
Expand Down Expand Up @@ -3400,6 +3404,8 @@ static void ParseArgs(int* argc,
} else if (strcmp(arg, "--prof-process") == 0) {
prof_process = true;
short_circuit = true;
} else if (strcmp(arg, "--zero-fill-buffers") == 0) {
zero_fill_all_buffers = true;
} else if (strcmp(arg, "--v8-options") == 0) {
new_v8_argv[new_v8_argc] = "--help";
new_v8_argc += 1;
Expand Down
11 changes: 9 additions & 2 deletions src/node_buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,14 @@
CHECK_NOT_OOB(end <= end_max); \
size_t length = end - start;

#define BUFFER_MALLOC(length) \
zero_fill_all_buffers ? calloc(length, 1) : malloc(length)

namespace node {

// if true, all Buffer and SlowBuffer instances will automatically zero-fill
bool zero_fill_all_buffers = false;

namespace Buffer {

using v8::ArrayBuffer;
Expand Down Expand Up @@ -220,7 +227,7 @@ MaybeLocal<Object> New(Isolate* isolate,
// nullptr for zero-sized allocation requests. Normalize by always using
// a nullptr.
if (length > 0) {
data = static_cast<char*>(malloc(length));
data = static_cast<char*>(BUFFER_MALLOC(length));

if (data == nullptr)
return Local<Object>();
Expand Down Expand Up @@ -266,7 +273,7 @@ MaybeLocal<Object> New(Environment* env, size_t length) {

void* data;
if (length > 0) {
data = malloc(length);
data = BUFFER_MALLOC(length);
if (data == nullptr)
return Local<Object>();
} else {
Expand Down
3 changes: 3 additions & 0 deletions src/node_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
#include "v8.h"

namespace node {

extern bool zero_fill_all_buffers;

namespace Buffer {

static const unsigned int kMaxLength =
Expand Down
30 changes: 30 additions & 0 deletions test/parallel/test-buffer-zero-fill-cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict';
// Flags: --zero-fill-buffers

// when using --zero-fill-buffers, every Buffer and SlowBuffer
// instance must be zero filled upon creation

require('../common');
const SlowBuffer = require('buffer').SlowBuffer;
const assert = require('assert');

function isZeroFilled(buf) {
for (let n = 0; n < buf.length; n++)
if (buf[n] > 0) return false;
return true;
}

// This can be somewhat unreliable because the
// allocated memory might just already happen to
// contain all zeroes. The test is run multiple
// times to improve the reliability.
for (let i = 0; i < 50; i++) {
const bufs = [
SlowBuffer(20),
Buffer(20),
new SlowBuffer(20)
];
for (const buf of bufs) {
assert(isZeroFilled(buf));
}
}