Skip to content

Commit fb03e57

Browse files
jasnellMyles Borins
authored and
Myles Borins
committed
buffer: backport --zero-fill-buffers cli 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. PR-URL: #5745 Reviewed-By: Trevor Norris <[email protected]>
1 parent 55f8689 commit fb03e57

File tree

6 files changed

+70
-3
lines changed

6 files changed

+70
-3
lines changed

doc/api/buffer.markdown

+17
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,23 @@ for (var b of buf)
145145
Additionally, the [`buf.values()`][], [`buf.keys()`][], and
146146
[`buf.entries()`][] methods can be used to create iterators.
147147

148+
## The `--zero-fill-buffers` command line option
149+
150+
Node.js can be started using the `--zero-fill-buffers` command line option to
151+
force all newly allocated `Buffer` and `SlowBuffer` instances created using
152+
either `new Buffer(size)` and `new SlowBuffer(size)` to be *automatically
153+
zero-filled* upon creation. Use of this flag *changes the default behavior* of
154+
these methods and *can have a significant impact* on performance. Use of the
155+
`--zero-fill-buffers` option is recommended only when absolutely necessary to
156+
enforce that newly allocated `Buffer` instances cannot contain potentially
157+
sensitive data.
158+
159+
```
160+
$ node --zero-fill-buffers
161+
> Buffer(5);
162+
<Buffer 00 00 00 00 00>
163+
```
164+
148165
## Class: Buffer
149166

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

doc/node.1

+4
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ Process v8 profiler output generated using the v8 option \fB\-\-prof\fR
9595
.BR \-\-v8\-options
9696
Print v8 command line options.
9797

98+
.TP
99+
.BR \-\-zero\-fill\-buffers
100+
Automatically zero-fills all newly allocated Buffer and SlowBuffer instances.
101+
98102
.TP
99103
.BR \-\-tls\-cipher\-list =\fIlist\fR
100104
Specify an alternative default TLS cipher list. (Requires Node.js to be built with crypto support. (Default))

src/node.cc

+7-1
Original file line numberDiff line numberDiff line change
@@ -947,7 +947,9 @@ Local<Value> WinapiErrnoException(Isolate* isolate,
947947

948948

949949
void* ArrayBufferAllocator::Allocate(size_t size) {
950-
if (env_ == nullptr || !env_->array_buffer_allocator_info()->no_zero_fill())
950+
if (env_ == nullptr ||
951+
!env_->array_buffer_allocator_info()->no_zero_fill() ||
952+
zero_fill_all_buffers)
951953
return calloc(size, 1);
952954
env_->array_buffer_allocator_info()->reset_fill_flag();
953955
return malloc(size);
@@ -3283,6 +3285,8 @@ static void PrintHelp() {
32833285
"snapshots\n"
32843286
" --prof-process process v8 profiler output generated\n"
32853287
" using --prof\n"
3288+
" --zero-fill-buffers automatically zero-fill all newly allocated\n"
3289+
" Buffer and SlowBuffer instances\n"
32863290
" --v8-options print v8 command line options\n"
32873291
#if HAVE_OPENSSL
32883292
" --tls-cipher-list=val use an alternative default TLS cipher list\n"
@@ -3422,6 +3426,8 @@ static void ParseArgs(int* argc,
34223426
} else if (strcmp(arg, "--prof-process") == 0) {
34233427
prof_process = true;
34243428
short_circuit = true;
3429+
} else if (strcmp(arg, "--zero-fill-buffers") == 0) {
3430+
zero_fill_all_buffers = true;
34253431
} else if (strcmp(arg, "--v8-options") == 0) {
34263432
new_v8_argv[new_v8_argc] = "--help";
34273433
new_v8_argc += 1;

src/node_buffer.cc

+9-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,14 @@
4848
CHECK_NOT_OOB(end <= end_max); \
4949
size_t length = end - start;
5050

51+
#define BUFFER_MALLOC(length) \
52+
zero_fill_all_buffers ? calloc(length, 1) : malloc(length)
53+
5154
namespace node {
55+
56+
// if true, all Buffer and SlowBuffer instances will automatically zero-fill
57+
bool zero_fill_all_buffers = false;
58+
5259
namespace Buffer {
5360

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

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

267274
void* data;
268275
if (length > 0) {
269-
data = malloc(length);
276+
data = BUFFER_MALLOC(length);
270277
if (data == nullptr)
271278
return Local<Object>();
272279
} else {

src/node_buffer.h

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
#include "v8.h"
66

77
namespace node {
8+
9+
extern bool zero_fill_all_buffers;
10+
811
namespace Buffer {
912

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

0 commit comments

Comments
 (0)