diff --git a/doc/api/buffer.markdown b/doc/api/buffer.markdown index ccc2e62ea3aa7b..9f0694b947f832 100644 --- a/doc/api/buffer.markdown +++ b/doc/api/buffer.markdown @@ -57,6 +57,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); + +``` + ## Class: Buffer The Buffer class is a global type for dealing with binary data directly. diff --git a/doc/node.1 b/doc/node.1 index ddeae7d71132ad..228174fdff979a 100644 --- a/doc/node.1 +++ b/doc/node.1 @@ -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) diff --git a/src/node.cc b/src/node.cc index c4b12a2f746309..39bf0e09b13d92 100644 --- a/src/node.cc +++ b/src/node.cc @@ -2635,6 +2635,8 @@ static void PrintHelp() { " --no-deprecation silence deprecation warnings\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 HAVE_OPENSSL " --enable-ssl3 enable ssl3\n" @@ -2719,6 +2721,9 @@ static void ParseArgs(int argc, char **argv) { argv[i] = const_cast(""); } else if (strcmp(arg, "--v8-options") == 0) { argv[i] = const_cast("--help"); + } else if (strcmp(arg, "--zero-fill-buffers") == 0) { + argv[i] = const_cast(""); + zero_fill_all_buffers = true; } else if (strcmp(arg, "--no-deprecation") == 0) { argv[i] = const_cast(""); no_deprecation = true; diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 8153c8319a7fe8..712c707cf11d86 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -31,13 +31,22 @@ #include #include // memcpy #include +#include #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define BUFFER_CLASS_ID (0xBABE) +#define BUFFER_MALLOC(length) \ + zero_fill_all_buffers ? \ + static_cast(calloc(length, 1)) : \ + new char[length] + namespace node { +// if true, all Buffer and SlowBuffer instances will automatically zero-fill +bool zero_fill_all_buffers = false; + using namespace v8; #define SLICE_ARGS(start_arg, end_arg) \ @@ -178,7 +187,7 @@ void Buffer::Replace(char *data, size_t length, if (callback_) { data_ = data; } else if (length_) { - data_ = new char[length_]; + data_ = BUFFER_MALLOC(length_); if (data) memcpy(data_, data, length_); V8::AdjustAmountOfExternalAllocatedMemory(sizeof(Buffer) + length_); diff --git a/src/node_buffer.h b/src/node_buffer.h index cb401b3b7231d2..c5af79c0ac8039 100644 --- a/src/node_buffer.h +++ b/src/node_buffer.h @@ -62,6 +62,7 @@ namespace node { */ +extern bool zero_fill_all_buffers; class NODE_EXTERN Buffer: public ObjectWrap { public: diff --git a/test/simple/test-buffer-zero-fill-cli.js b/test/simple/test-buffer-zero-fill-cli.js new file mode 100644 index 00000000000000..5d63a0568e3530 --- /dev/null +++ b/test/simple/test-buffer-zero-fill-cli.js @@ -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) + ]; + bufs.forEach(function(buf) { + assert(isZeroFilled(buf)); + }); +}