Skip to content

Commit 9841681

Browse files
committed
buffer: backport --zero-fill-buffers command line option
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.
1 parent ab907eb commit 9841681

File tree

7 files changed

+65
-2
lines changed

7 files changed

+65
-2
lines changed

doc/api/buffer.markdown

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,23 @@ While more efficient, it introduces subtle incompatibilities with the typed
5353
arrays specification. `ArrayBuffer#slice()` makes a copy of the slice while
5454
`Buffer#slice()` creates a view.
5555

56+
## The `--zero-fill-buffers` command line option
57+
58+
Node.js can be started using the `--zero-fill-buffers` command line option to
59+
force all newly allocated `Buffer` and `SlowBuffer` instances created using
60+
either `new Buffer(size)` and `new SlowBuffer(size)` to be *automatically
61+
zero-filled* upon creation. Use of this flag *changes the default behavior* of
62+
these methods and *can have a significant impact* on performance. Use of the
63+
`--zero-fill-buffers` option is recommended only when absolutely necessary to
64+
enforce that newly allocated `Buffer` instances cannot contain potentially
65+
sensitive data.
66+
67+
```
68+
$ node --zero-fill-buffers
69+
> Buffer(5);
70+
<Buffer 00 00 00 00 00>
71+
```
72+
5673
## Class: Buffer
5774

5875
The Buffer class is a global type for dealing with binary data directly.

doc/node.1

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ and servers.
5858

5959
--throw-deprecation throw errors on deprecations
6060

61+
--zero-fill-buffers Automatically zero-fills all newly allocated Buffer
62+
and SlowBuffer instances.
63+
6164
--v8-options print v8 command line options
6265

6366
--max-stack-size=val set max v8 stack size (bytes)

src/node.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ void* ArrayBufferAllocator::Allocate(size_t length) {
186186

187187

188188
void* ArrayBufferAllocator::AllocateUninitialized(size_t length) {
189+
if (zero_fill_all_buffers)
190+
return ArrayBufferAllocator::Allocate(length);
189191
if (length > kMaxLength)
190192
return NULL;
191193
return new char[length];
@@ -3003,6 +3005,8 @@ static void PrintHelp() {
30033005
"function is used\n"
30043006
" --trace-deprecation show stack traces on deprecations\n"
30053007
" --v8-options print v8 command line options\n"
3008+
" --zero-fill-buffers automatically zero-fill all newly allocated\n"
3009+
" Buffer and SlowBuffer instances\n"
30063010
" --max-stack-size=val set max v8 stack size (bytes)\n"
30073011
#if defined(NODE_HAVE_I18N_SUPPORT)
30083012
" --icu-data-dir=dir set ICU data load path to dir\n"
@@ -3137,6 +3141,8 @@ static void ParseArgs(int* argc,
31373141
} else if (strcmp(arg, "--v8-options") == 0) {
31383142
new_v8_argv[new_v8_argc] = "--help";
31393143
new_v8_argc += 1;
3144+
} else if (strcmp(arg, "--zero-fill-buffers") == 0) {
3145+
zero_fill_all_buffers = true;
31403146
#if defined(NODE_HAVE_I18N_SUPPORT)
31413147
} else if (strncmp(arg, "--icu-data-dir=", 15) == 0) {
31423148
icu_data_dir = arg + 15;

src/node_buffer.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ Local<Object> New(Environment* env, size_t length) {
152152
// approach if v8 provided one.
153153
char* data;
154154
if (length > 0) {
155-
data = static_cast<char*>(malloc(length));
155+
data = static_cast<char*>(BUFFER_MALLOC(length));
156156
if (data == NULL)
157157
FatalError("node::Buffer::New(size_t)", "Out Of Memory");
158158
} else {

src/smalloc.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434
#define ALLOC_ID (0xA10C)
3535

3636
namespace node {
37+
38+
// if true, all Buffer and SlowBuffer instances will automatically zero-fill
39+
bool zero_fill_all_buffers = false;
40+
3741
namespace smalloc {
3842

3943
using v8::Context;
@@ -329,7 +333,7 @@ void Alloc(Environment* env,
329333
if (length == 0)
330334
return Alloc(env, obj, NULL, length, type);
331335

332-
char* data = static_cast<char*>(malloc(length));
336+
char* data = static_cast<char*>(BUFFER_MALLOC(length));
333337
if (data == NULL) {
334338
FatalError("node::smalloc::Alloc(v8::Handle<v8::Object>, size_t,"
335339
" v8::ExternalArrayType)", "Out Of Memory");

src/smalloc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727

2828
namespace node {
2929

30+
#define BUFFER_MALLOC(length) \
31+
zero_fill_all_buffers ? calloc(length, 1) : malloc(length)
32+
extern bool zero_fill_all_buffers;
33+
3034
// Forward declaration
3135
class Environment;
3236

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Flags: --zero-fill-buffers
2+
3+
// when using --zero-fill-buffers, every Buffer and SlowBuffer
4+
// instance must be zero filled upon creation
5+
6+
require('../common');
7+
var SlowBuffer = require('buffer').SlowBuffer;
8+
var assert = require('assert');
9+
10+
function isZeroFilled(buf) {
11+
for (var n = 0; n < buf.length; n++)
12+
if (buf[n] > 0) return false;
13+
return true;
14+
}
15+
16+
// This can be somewhat unreliable because the
17+
// allocated memory might just already happen to
18+
// contain all zeroes. The test is run multiple
19+
// times to improve the reliability.
20+
for (var i = 0; i < 50; i++) {
21+
var bufs = [
22+
SlowBuffer(20),
23+
Buffer(20),
24+
new SlowBuffer(20)
25+
];
26+
for (var buf of bufs) {
27+
assert(isZeroFilled(buf));
28+
}
29+
}

0 commit comments

Comments
 (0)