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 Mar 17, 2016
1 parent ab907eb commit 9841681
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 2 deletions.
17 changes: 17 additions & 0 deletions doc/api/buffer.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,23 @@ While more efficient, it introduces subtle incompatibilities with the typed
arrays specification. `ArrayBuffer#slice()` makes a copy of the slice while
`Buffer#slice()` creates a view.

## 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/node.1
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ and servers.

--throw-deprecation throw errors on deprecations

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

--v8-options print v8 command line options

--max-stack-size=val set max v8 stack size (bytes)
Expand Down
6 changes: 6 additions & 0 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ void* ArrayBufferAllocator::Allocate(size_t length) {


void* ArrayBufferAllocator::AllocateUninitialized(size_t length) {
if (zero_fill_all_buffers)
return ArrayBufferAllocator::Allocate(length);
if (length > kMaxLength)
return NULL;
return new char[length];
Expand Down Expand Up @@ -3003,6 +3005,8 @@ static void PrintHelp() {
"function is used\n"
" --trace-deprecation show stack traces on deprecations\n"
" --v8-options print v8 command line options\n"
" --zero-fill-buffers automatically zero-fill all newly allocated\n"
" Buffer and SlowBuffer instances\n"
" --max-stack-size=val set max v8 stack size (bytes)\n"
#if defined(NODE_HAVE_I18N_SUPPORT)
" --icu-data-dir=dir set ICU data load path to dir\n"
Expand Down Expand Up @@ -3137,6 +3141,8 @@ static void ParseArgs(int* argc,
} else if (strcmp(arg, "--v8-options") == 0) {
new_v8_argv[new_v8_argc] = "--help";
new_v8_argc += 1;
} else if (strcmp(arg, "--zero-fill-buffers") == 0) {
zero_fill_all_buffers = true;
#if defined(NODE_HAVE_I18N_SUPPORT)
} else if (strncmp(arg, "--icu-data-dir=", 15) == 0) {
icu_data_dir = arg + 15;
Expand Down
2 changes: 1 addition & 1 deletion src/node_buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ Local<Object> New(Environment* env, size_t length) {
// approach if v8 provided one.
char* data;
if (length > 0) {
data = static_cast<char*>(malloc(length));
data = static_cast<char*>(BUFFER_MALLOC(length));
if (data == NULL)
FatalError("node::Buffer::New(size_t)", "Out Of Memory");
} else {
Expand Down
6 changes: 5 additions & 1 deletion src/smalloc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
#define ALLOC_ID (0xA10C)

namespace node {

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

namespace smalloc {

using v8::Context;
Expand Down Expand Up @@ -329,7 +333,7 @@ void Alloc(Environment* env,
if (length == 0)
return Alloc(env, obj, NULL, length, type);

char* data = static_cast<char*>(malloc(length));
char* data = static_cast<char*>(BUFFER_MALLOC(length));
if (data == NULL) {
FatalError("node::smalloc::Alloc(v8::Handle<v8::Object>, size_t,"
" v8::ExternalArrayType)", "Out Of Memory");
Expand Down
4 changes: 4 additions & 0 deletions src/smalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@

namespace node {

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

// Forward declaration
class Environment;

Expand Down
29 changes: 29 additions & 0 deletions test/simple/test-buffer-zero-fill-cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Flags: --zero-fill-buffers

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

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

function isZeroFilled(buf) {
for (var 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 (var i = 0; i < 50; i++) {
var bufs = [
SlowBuffer(20),
Buffer(20),
new SlowBuffer(20)
];
for (var buf of bufs) {
assert(isZeroFilled(buf));
}
}

0 comments on commit 9841681

Please sign in to comment.