aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/api/errors.md13
-rw-r--r--src/node_buffer.cc22
-rw-r--r--src/node_errors.h3
-rw-r--r--test/addons/non-node-context/binding.cc21
-rw-r--r--test/addons/non-node-context/test-make-buffer.js22
5 files changed, 70 insertions, 11 deletions
diff --git a/doc/api/errors.md b/doc/api/errors.md
index bdabc48a7d..aecb5282e7 100644
--- a/doc/api/errors.md
+++ b/doc/api/errors.md
@@ -613,6 +613,19 @@ An attempt was made to register something that is not a function as an
The type of an asynchronous resource was invalid. Note that users are also able
to define their own types if using the public embedder API.
+<a id="ERR_BUFFER_CONTEXT_NOT_AVAILABLE"></a>
+### ERR_BUFFER_CONTEXT_NOT_AVAILABLE
+
+An attempt was made to create a Node.js `Buffer` instance from addon or embedder
+code, while in a JS engine Context that is not associated with a Node.js
+instance. The data passed to the `Buffer` method will have been released
+by the time the method returns.
+
+When encountering this error, a possible alternative to creating a `Buffer`
+instance is to create a normal `Uint8Array`, which only differs in the
+prototype of the resulting object. `Uint8Array`s are generally accepted in all
+Node.js core APIs where `Buffer`s are; they are available in all Contexts.
+
<a id="ERR_BUFFER_OUT_OF_BOUNDS"></a>
### ERR_BUFFER_OUT_OF_BOUNDS
diff --git a/src/node_buffer.cc b/src/node_buffer.cc
index d4f7c75163..2a2fb45e7a 100644
--- a/src/node_buffer.cc
+++ b/src/node_buffer.cc
@@ -271,7 +271,10 @@ MaybeLocal<Object> New(Isolate* isolate, size_t length) {
EscapableHandleScope handle_scope(isolate);
Local<Object> obj;
Environment* env = Environment::GetCurrent(isolate);
- CHECK_NOT_NULL(env); // TODO(addaleax): Handle nullptr here.
+ if (env == nullptr) {
+ THROW_ERR_BUFFER_CONTEXT_NOT_AVAILABLE(isolate);
+ return MaybeLocal<Object>();
+ }
if (Buffer::New(env, length).ToLocal(&obj))
return handle_scope.Escape(obj);
return Local<Object>();
@@ -314,7 +317,10 @@ MaybeLocal<Object> New(Environment* env, size_t length) {
MaybeLocal<Object> Copy(Isolate* isolate, const char* data, size_t length) {
EscapableHandleScope handle_scope(isolate);
Environment* env = Environment::GetCurrent(isolate);
- CHECK_NOT_NULL(env); // TODO(addaleax): Handle nullptr here.
+ if (env == nullptr) {
+ THROW_ERR_BUFFER_CONTEXT_NOT_AVAILABLE(isolate);
+ return MaybeLocal<Object>();
+ }
Local<Object> obj;
if (Buffer::Copy(env, data, length).ToLocal(&obj))
return handle_scope.Escape(obj);
@@ -364,7 +370,11 @@ MaybeLocal<Object> New(Isolate* isolate,
void* hint) {
EscapableHandleScope handle_scope(isolate);
Environment* env = Environment::GetCurrent(isolate);
- CHECK_NOT_NULL(env); // TODO(addaleax): Handle nullptr here.
+ if (env == nullptr) {
+ callback(data, hint);
+ THROW_ERR_BUFFER_CONTEXT_NOT_AVAILABLE(isolate);
+ return MaybeLocal<Object>();
+ }
Local<Object> obj;
if (Buffer::New(env, data, length, callback, hint).ToLocal(&obj))
return handle_scope.Escape(obj);
@@ -403,7 +413,11 @@ MaybeLocal<Object> New(Environment* env,
MaybeLocal<Object> New(Isolate* isolate, char* data, size_t length) {
EscapableHandleScope handle_scope(isolate);
Environment* env = Environment::GetCurrent(isolate);
- CHECK_NOT_NULL(env); // TODO(addaleax): Handle nullptr here.
+ if (env == nullptr) {
+ free(data);
+ THROW_ERR_BUFFER_CONTEXT_NOT_AVAILABLE(isolate);
+ return MaybeLocal<Object>();
+ }
Local<Object> obj;
if (Buffer::New(env, data, length).ToLocal(&obj))
return handle_scope.Escape(obj);
diff --git a/src/node_errors.h b/src/node_errors.h
index a958eccf8a..a435695693 100644
--- a/src/node_errors.h
+++ b/src/node_errors.h
@@ -21,6 +21,7 @@ namespace node {
// a `Local<Value>` containing the TypeError with proper code and message
#define ERRORS_WITH_CODE(V) \
+ V(ERR_BUFFER_CONTEXT_NOT_AVAILABLE, Error) \
V(ERR_BUFFER_OUT_OF_BOUNDS, RangeError) \
V(ERR_BUFFER_TOO_LARGE, Error) \
V(ERR_CANNOT_TRANSFER_OBJECT, TypeError) \
@@ -64,6 +65,8 @@ namespace node {
// Errors with predefined static messages
#define PREDEFINED_ERROR_MESSAGES(V) \
+ V(ERR_BUFFER_CONTEXT_NOT_AVAILABLE, \
+ "Buffer is not available for the current Context") \
V(ERR_CANNOT_TRANSFER_OBJECT, "Cannot transfer object of unsupported type")\
V(ERR_CLOSED_MESSAGE_PORT, "Cannot send data on closed MessagePort") \
V(ERR_CONSTRUCT_CALL_REQUIRED, "Cannot call constructor without `new`") \
diff --git a/test/addons/non-node-context/binding.cc b/test/addons/non-node-context/binding.cc
index 324f5c5a1e..776786cef5 100644
--- a/test/addons/non-node-context/binding.cc
+++ b/test/addons/non-node-context/binding.cc
@@ -1,4 +1,5 @@
#include <node.h>
+#include <node_buffer.h>
#include <assert.h>
namespace {
@@ -15,6 +16,17 @@ using v8::Script;
using v8::String;
using v8::Value;
+inline void MakeBufferInNewContext(
+ const v8::FunctionCallbackInfo<v8::Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+ Local<Context> context = Context::New(isolate);
+ Context::Scope context_scope(context);
+
+ // This should throw an exception, rather than actually do anything.
+ MaybeLocal<Object> buf = node::Buffer::Copy(isolate, "foo", 3);
+ assert(buf.IsEmpty());
+}
+
inline void RunInNewContext(
const v8::FunctionCallbackInfo<v8::Value>& args) {
Isolate* isolate = args.GetIsolate();
@@ -41,13 +53,8 @@ inline void RunInNewContext(
inline void Initialize(Local<Object> exports,
Local<Value> module,
Local<Context> context) {
- Isolate* isolate = context->GetIsolate();
- Local<String> key = String::NewFromUtf8(
- isolate, "runInNewContext", NewStringType::kNormal).ToLocalChecked();
- Local<Function> value = FunctionTemplate::New(isolate, RunInNewContext)
- ->GetFunction(context)
- .ToLocalChecked();
- assert(exports->Set(context, key, value).IsJust());
+ NODE_SET_METHOD(exports, "runInNewContext", RunInNewContext);
+ NODE_SET_METHOD(exports, "makeBufferInNewContext", MakeBufferInNewContext);
}
} // anonymous namespace
diff --git a/test/addons/non-node-context/test-make-buffer.js b/test/addons/non-node-context/test-make-buffer.js
new file mode 100644
index 0000000000..9b17fa4ee9
--- /dev/null
+++ b/test/addons/non-node-context/test-make-buffer.js
@@ -0,0 +1,22 @@
+'use strict';
+
+const common = require('../../common');
+const assert = require('assert');
+const {
+ makeBufferInNewContext
+} = require(`./build/${common.buildType}/binding`);
+
+// Because the `Buffer` function and its protoype property only (currently)
+// exist in a Node.js instance’s main context, trying to create buffers from
+// another context throws an exception.
+
+try {
+ makeBufferInNewContext();
+} catch (exception) {
+ assert.strictEqual(exception.constructor.name, 'Error');
+ assert(!(exception.constructor instanceof Error));
+
+ assert.strictEqual(exception.code, 'ERR_BUFFER_CONTEXT_NOT_AVAILABLE');
+ assert.strictEqual(exception.message,
+ 'Buffer is not available for the current Context');
+}