Skip to content

Commit

Permalink
buffer: backport --zero-fill-buffers command line option
Browse files Browse the repository at this point in the history
This backports the --zero-fill-buffers command line flag introduced
in master. When used, all Buffer and SlowBuffer instances will zero
fill by default.

This does *not* backport any of the other Buffer API or behavior
changes.
  • Loading branch information
jasnell committed Jul 1, 2016
1 parent e319d76 commit f615770
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 3 deletions.
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
4 changes: 4 additions & 0 deletions doc/node.1
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ Process v8 profiler output generated using the v8 option \fB\-\-prof\fR
.BR \-\-v8\-options
Print v8 command line options.

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

.TP
.BR \-\-tls\-cipher\-list =\fIlist\fR
Specify an alternative default TLS cipher list. (Requires Node.js to be built with crypto support. (Default))
Expand Down
8 changes: 7 additions & 1 deletion src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -947,7 +947,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 @@ -3283,6 +3285,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 @@ -3422,6 +3426,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));
}
}

0 comments on commit f615770

Please sign in to comment.