diff --git a/lib/buffer.js b/lib/buffer.js index 48eca73b53b2e2..0f973ca7c1ebd0 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -23,11 +23,13 @@ 'use strict'; const binding = process.binding('buffer'); +const config = process.binding('config'); const { compare: compare_, compareOffset } = binding; const { isArrayBuffer, isSharedArrayBuffer, isUint8Array } = process.binding('util'); const bindingObj = {}; const internalUtil = require('internal/util'); +const pendingDeprecation = !!config.pendingDeprecation; class FastBuffer extends Uint8Array { constructor(arg1, arg2, arg3) { @@ -69,6 +71,15 @@ function createUnsafeArrayBuffer(size) { } } +function createRandomFillBuffer(size) { + zeroFill[0] = 3; + try { + return new ArrayBuffer(size); + } finally { + zeroFill[0] = 1; + } +} + function createPool() { poolSize = Buffer.poolSize; allocPool = createUnsafeArrayBuffer(poolSize); @@ -85,6 +96,12 @@ function alignPool() { } } +var bufferWarn = true; +const bufferWarning = 'The Buffer() and new Buffer() constructors are not ' + + 'recommended for use due to security and usability ' + + 'concerns. Please use the new Buffer.alloc(), ' + + 'Buffer.allocUnsafe(), or Buffer.from() construction ' + + 'methods instead.'; /** * The Buffer() construtor is deprecated in documentation and should not be * used moving forward. Rather, developers should use one of the three new @@ -97,13 +114,22 @@ function alignPool() { **/ function Buffer(arg, encodingOrOffset, length) { // Common case. + if (pendingDeprecation && bufferWarn) { + // This is a *pending* deprecation warning. It is not emitted by + // default unless the --pending-deprecation command-line flag is + // used or the NODE_PENDING_DEPRECATION=1 envvar is set. + process.emitWarning(bufferWarning, 'DeprecationWarning', 'DEP0005'); + bufferWarn = false; + } + if (typeof arg === 'number') { if (typeof encodingOrOffset === 'string') { throw new Error( 'If encoding is specified then the first argument must be a string' ); } - return Buffer.allocUnsafe(arg); + assertSize(arg); + return new FastBuffer(createRandomFillBuffer(arg)); } return Buffer.from(arg, encodingOrOffset, length); } diff --git a/src/node.cc b/src/node.cc index fda6c3f257730b..84b3702b591d34 100644 --- a/src/node.cc +++ b/src/node.cc @@ -209,6 +209,10 @@ bool trace_warnings = false; // that is used by lib/module.js bool config_preserve_symlinks = false; +// Set by ParseArgs when --pending-deprecation or NODE_PENDING_DEPRECATION +// is used. +bool config_pending_deprecation = false; + // Set in node.cc by ParseArgs when --redirect-warnings= is used. std::string config_warning_file; // NOLINT(runtime/string) @@ -1036,10 +1040,15 @@ Local WinapiErrnoException(Isolate* isolate, void* ArrayBufferAllocator::Allocate(size_t size) { - if (zero_fill_field_ || zero_fill_all_buffers) + if (zero_fill_all_buffers || zero_fill_field_ == 1) { return node::UncheckedCalloc(size); - else - return node::UncheckedMalloc(size); + } else if (zero_fill_field_ == 3) { + void* mem = node::UncheckedMalloc(size); + if (mem != nullptr) + memset(mem, random_fill_value_, size); + return mem; + } + return node::UncheckedMalloc(size); } static bool DomainHasErrorHandler(const Environment* env, @@ -3739,6 +3748,8 @@ static void ParseArgs(int* argc, short_circuit = true; } else if (strcmp(arg, "--zero-fill-buffers") == 0) { zero_fill_all_buffers = true; + } else if (strcmp(arg, "--pending-deprecation") == 0) { + config_pending_deprecation = true; } else if (strcmp(arg, "--v8-options") == 0) { new_v8_argv[new_v8_argc] = "--help"; new_v8_argc += 1; @@ -4248,6 +4259,12 @@ void Init(int* argc, V8::SetFlagsFromString(NODE_V8_OPTIONS, sizeof(NODE_V8_OPTIONS) - 1); #endif + { + std::string text; + config_pending_deprecation = + SafeGetenv("NODE_PENDING_DEPRECATION", &text) && text[0] == '1'; + } + // Allow for environment set preserving symlinks. { std::string text; diff --git a/src/node_config.cc b/src/node_config.cc index 5c9c51585baf3a..8f9cc5aff62120 100644 --- a/src/node_config.cc +++ b/src/node_config.cc @@ -49,6 +49,9 @@ void InitConfig(Local target, if (config_preserve_symlinks) READONLY_BOOLEAN_PROPERTY("preserveSymlinks"); + if (config_pending_deprecation) + READONLY_BOOLEAN_PROPERTY("pendingDeprecation"); + if (!config_warning_file.empty()) { Local name = OneByteString(env->isolate(), "warningFile"); Local value = String::NewFromUtf8(env->isolate(), diff --git a/src/node_internals.h b/src/node_internals.h index ff1f1cd11dba4e..569149957bf2e7 100644 --- a/src/node_internals.h +++ b/src/node_internals.h @@ -70,6 +70,10 @@ extern bool config_preserve_symlinks; // it to stderr. extern std::string config_warning_file; // NOLINT(runtime/string) +// Set in node.cc by ParseArgs when --pending-deprecation or +// NODE_PENDING_DEPRECATION is used +extern bool config_pending_deprecation; + // Tells whether it is safe to call v8::Isolate::GetCurrent(). extern bool v8_initialized; @@ -196,6 +200,11 @@ inline bool IsBigEndian() { class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { public: + ArrayBufferAllocator() { + unsigned int seed = time(NULL); + random_fill_value_ = rand_r(&seed) % 256; + } + inline uint32_t* zero_fill_field() { return &zero_fill_field_; } virtual void* Allocate(size_t size); // Defined in src/node.cc @@ -205,6 +214,7 @@ class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { private: uint32_t zero_fill_field_ = 1; // Boolean but exposed as uint32 to JS land. + uint8_t random_fill_value_; }; // Clear any domain and/or uncaughtException handlers to force the error's diff --git a/test/parallel/test-buffer-pending-deprecation.js b/test/parallel/test-buffer-pending-deprecation.js new file mode 100644 index 00000000000000..fcce8814cdbd6f --- /dev/null +++ b/test/parallel/test-buffer-pending-deprecation.js @@ -0,0 +1,15 @@ +// Flags: --pending-deprecation --no-warnings +'use strict'; + +const common = require('../common'); +const Buffer = require('buffer').Buffer; + +const bufferWarning = 'The Buffer() and new Buffer() constructors are not ' + + 'recommended for use due to security and usability ' + + 'concerns. Please use the new Buffer.alloc(), ' + + 'Buffer.allocUnsafe(), or Buffer.from() construction ' + + 'methods instead.'; + +common.expectWarning('DeprecationWarning', bufferWarning); + +new Buffer(10);