Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

n-api: add optional string length parameter #15343

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 14 additions & 1 deletion doc/api/n-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -552,11 +552,18 @@ thrown to immediately terminate the process.
added: v8.2.0
-->
```C
NAPI_NO_RETURN void napi_fatal_error(const char* location, const char* message);
NAPI_NO_RETURN void napi_fatal_error(const char* location,
size_t location_len,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should NAPI_EXTERN be added here ?

const char* message,
size_t message_len);
```

- `[in] location`: Optional location at which the error occurred.
- `[in] location_len`: The length of the location in bytes, or -1 if it is
null-terminated.
- `[in] message`: The message associated with the error.
- `[in] message_len`: The length of the message in bytes, or -1 if it is
null-terminated.

The function call does not return, the process will be terminated.

Expand Down Expand Up @@ -1248,6 +1255,7 @@ added: v8.0.0
```C
napi_status napi_create_function(napi_env env,
const char* utf8name,
size_t length,
napi_callback cb,
void* data,
napi_value* result)
Expand All @@ -1256,6 +1264,8 @@ napi_status napi_create_function(napi_env env,
- `[in] env`: The environment that the API is invoked under.
- `[in] utf8name`: A string representing the name of the function encoded as
UTF8.
- `[in] length`: The length of the utf8name in bytes, or -1 if it is
null-terminated.
- `[in] cb`: A function pointer to the native function to be invoked when the
created function is invoked from JavaScript.
- `[in] data`: Optional arbitrary context data to be passed into the native
Expand Down Expand Up @@ -3026,6 +3036,7 @@ added: v8.0.0
```C
napi_status napi_define_class(napi_env env,
const char* utf8name,
size_t length,
napi_callback constructor,
void* data,
size_t property_count,
Expand All @@ -3037,6 +3048,8 @@ napi_status napi_define_class(napi_env env,
- `[in] utf8name`: Name of the JavaScript constructor function; this is
not required to be the same as the C++ class name, though it is recommended
for clarity.
- `[in] length`: The length of the utf8name in bytes, or -1 if it is
null-terminated.
- `[in] constructor`: Callback function that handles constructing instances
of the class. (This should be a static method on the class, not an actual
C++ constructor function.)
Expand Down
24 changes: 20 additions & 4 deletions src/node_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -933,12 +933,27 @@ napi_status napi_get_last_error_info(napi_env env,
}

NAPI_NO_RETURN void napi_fatal_error(const char* location,
const char* message) {
node::FatalError(location, message);
size_t location_len,
const char* message,
size_t message_len) {
char* location_string = const_cast<char*>(location);
char* message_string = const_cast<char*>(message);
if (location_len != -1) {
location_string = (char*) malloc(location_len * sizeof(char) + 1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought we were going to use stack allocation, won't the malloc's result in a memory leak ?

Copy link
Member

@mhdawson mhdawson Sep 15, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sampsongao pointed out that the process will terminate when we call napi_fatal_error so it should be ok.

strncpy(location_string, location, location_len);
location_string[location_len] = '\0';
}
if (message_len != -1) {
message_string = (char*) malloc(message_len * sizeof(char) + 1);
strncpy(message_string, message, message_len);
message_string[message_len] = '\0';
}
node::FatalError(location_string, message_string);
}

napi_status napi_create_function(napi_env env,
const char* utf8name,
size_t length,
napi_callback cb,
void* callback_data,
napi_value* result) {
Expand All @@ -965,7 +980,7 @@ napi_status napi_create_function(napi_env env,

if (utf8name != nullptr) {
v8::Local<v8::String> name_string;
CHECK_NEW_FROM_UTF8(env, name_string, utf8name);
CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
return_value->SetName(name_string);
}

Expand All @@ -976,6 +991,7 @@ napi_status napi_create_function(napi_env env,

napi_status napi_define_class(napi_env env,
const char* utf8name,
size_t length,
napi_callback constructor,
void* callback_data,
size_t property_count,
Expand All @@ -997,7 +1013,7 @@ napi_status napi_define_class(napi_env env,
isolate, v8impl::FunctionCallbackWrapper::Invoke, cbdata);

v8::Local<v8::String> name_string;
CHECK_NEW_FROM_UTF8(env, name_string, utf8name);
CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
tpl->SetClassName(name_string);

size_t static_property_count = 0;
Expand Down
6 changes: 5 additions & 1 deletion src/node_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,9 @@ napi_get_last_error_info(napi_env env,
const napi_extended_error_info** result);

NAPI_EXTERN NAPI_NO_RETURN void napi_fatal_error(const char* location,
const char* message);
size_t location_len,
const char* message,
size_t message_len);

// Getters for defined singletons
NAPI_EXTERN napi_status napi_get_undefined(napi_env env, napi_value* result);
Expand Down Expand Up @@ -154,6 +156,7 @@ NAPI_EXTERN napi_status napi_create_symbol(napi_env env,
napi_value* result);
NAPI_EXTERN napi_status napi_create_function(napi_env env,
const char* utf8name,
size_t length,
napi_callback cb,
void* data,
napi_value* result);
Expand Down Expand Up @@ -336,6 +339,7 @@ NAPI_EXTERN napi_status napi_get_new_target(napi_env env,
NAPI_EXTERN napi_status
napi_define_class(napi_env env,
const char* utf8name,
size_t length,
napi_callback constructor,
void* data,
size_t property_count,
Expand Down
2 changes: 1 addition & 1 deletion test/addons-napi/4_object_factory/binding.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ napi_value CreateObject(napi_env env, napi_callback_info info) {

napi_value Init(napi_env env, napi_value exports) {
NAPI_CALL(env,
napi_create_function(env, "exports", CreateObject, NULL, &exports));
napi_create_function(env, "exports", -1, CreateObject, NULL, &exports));
return exports;
}

Expand Down
6 changes: 2 additions & 4 deletions test/addons-napi/5_function_factory/binding.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,19 @@
napi_value MyFunction(napi_env env, napi_callback_info info) {
napi_value str;
NAPI_CALL(env, napi_create_string_utf8(env, "hello world", -1, &str));

return str;
}

napi_value CreateFunction(napi_env env, napi_callback_info info) {
napi_value fn;
NAPI_CALL(env,
napi_create_function(env, "theFunction", MyFunction, NULL, &fn));

napi_create_function(env, "theFunction", -1, MyFunction, NULL, &fn));
return fn;
}

napi_value Init(napi_env env, napi_value exports) {
NAPI_CALL(env,
napi_create_function(env, "exports", CreateFunction, NULL, &exports));
napi_create_function(env, "exports", -1, CreateFunction, NULL, &exports));
return exports;
}

Expand Down
2 changes: 1 addition & 1 deletion test/addons-napi/6_object_wrap/myobject.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ void MyObject::Init(napi_env env, napi_value exports) {

napi_value cons;
NAPI_CALL_RETURN_VOID(env,
napi_define_class(env, "MyObject", New, nullptr, 3, properties, &cons));
napi_define_class(env, "MyObject", -1, New, nullptr, 3, properties, &cons));

NAPI_CALL_RETURN_VOID(env, napi_create_reference(env, cons, 1, &constructor));

Expand Down
2 changes: 1 addition & 1 deletion test/addons-napi/7_factory_wrap/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ napi_value Init(napi_env env, napi_value exports) {
NAPI_CALL(env, MyObject::Init(env));

NAPI_CALL(env,
napi_create_function(env, "exports", CreateObject, NULL, &exports));
napi_create_function(env, "exports", -1, CreateObject, NULL, &exports));
return exports;
}

Expand Down
2 changes: 1 addition & 1 deletion test/addons-napi/7_factory_wrap/myobject.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ napi_status MyObject::Init(napi_env env) {

napi_value cons;
status =
napi_define_class(env, "MyObject", New, nullptr, 1, properties, &cons);
napi_define_class(env, "MyObject", -1, New, nullptr, 1, properties, &cons);
if (status != napi_ok) return status;

status = napi_create_reference(env, cons, 1, &constructor);
Expand Down
2 changes: 1 addition & 1 deletion test/addons-napi/8_passing_wrapped/myobject.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ napi_status MyObject::Init(napi_env env) {
napi_status status;

napi_value cons;
status = napi_define_class(env, "MyObject", New, nullptr, 0, nullptr, &cons);
status = napi_define_class(env, "MyObject", -1, New, nullptr, 0, nullptr, &cons);
if (status != napi_ok) return status;

status = napi_create_reference(env, cons, 1, &constructor);
Expand Down
4 changes: 4 additions & 0 deletions test/addons-napi/test_constructor/binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
{
"target_name": "test_constructor",
"sources": [ "test_constructor.c" ]
},
{
"target_name": "test_constructor_name",
"sources": [ "test_constructor_name.c" ]
}
]
}
8 changes: 8 additions & 0 deletions test/addons-napi/test_constructor/test2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'use strict';
const common = require('../../common');
const assert = require('assert');

// Testing api calls for a constructor that defines properties
const TestConstructor =
require(`./build/${common.buildType}/test_constructor_name`);
assert.equal(TestConstructor.name, 'MyObject');
2 changes: 1 addition & 1 deletion test/addons-napi/test_constructor/test_constructor.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ napi_value Init(napi_env env, napi_value exports) {
};

napi_value cons;
NAPI_CALL(env, napi_define_class(env, "MyObject", New,
NAPI_CALL(env, napi_define_class(env, "MyObject", -1, New,
NULL, sizeof(properties)/sizeof(*properties), properties, &cons));

NAPI_CALL(env, napi_create_reference(env, cons, 1, &constructor_));
Expand Down
23 changes: 23 additions & 0 deletions test/addons-napi/test_constructor/test_constructor_name.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include <node_api.h>
#include "../common.h"

napi_ref constructor_;

napi_value New(napi_env env, napi_callback_info info) {
napi_value _this;
NAPI_CALL(env, napi_get_cb_info(env, info, NULL, NULL, &_this, NULL));

return _this;
}

napi_value Init(napi_env env, napi_value exports) {
napi_value cons;
NAPI_CALL(env, napi_define_class(
env, "MyObject_Extra", 8, New, NULL, 0, NULL, &cons));

NAPI_CALL(env,
napi_create_reference(env, cons, 1, &constructor_));
return cons;
}

NAPI_MODULE(addon, Init)
2 changes: 1 addition & 1 deletion test/addons-napi/test_env_sharing/compare_env.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ napi_value compare(napi_env env, napi_callback_info info) {
}

napi_value Init(napi_env env, napi_value exports) {
NAPI_CALL(env, napi_create_function(env, "exports", compare, NULL, &exports));
NAPI_CALL(env, napi_create_function(env, "exports", -1, compare, NULL, &exports));
return exports;
}

Expand Down
18 changes: 18 additions & 0 deletions test/addons-napi/test_fatal/test2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use strict';
const common = require('../../common');
const assert = require('assert');
const child_process = require('child_process');
const test_fatal = require(`./build/${common.buildType}/test_fatal`);

// Test in a child process because the test code will trigger a fatal error
// that crashes the process.
if (process.argv[2] === 'child') {
test_fatal.TestStringLength();
return;
}

const p = child_process.spawnSync(
process.execPath, [ '--napi-modules', __filename, 'child' ]);
assert.ifError(p.error);
assert.ok(p.stderr.toString().includes(
'FATAL ERROR: test_fatal::Test fatal message'));
8 changes: 7 additions & 1 deletion test/addons-napi/test_fatal/test_fatal.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@
#include "../common.h"

napi_value Test(napi_env env, napi_callback_info info) {
napi_fatal_error("test_fatal::Test", "fatal message");
napi_fatal_error("test_fatal::Test", -1, "fatal message", -1);
return NULL;
}

napi_value TestStringLength(napi_env env, napi_callback_info info) {
napi_fatal_error("test_fatal::TestStringLength", 16, "fatal message", 13);
return NULL;
}

napi_value Init(napi_env env, napi_value exports) {
napi_property_descriptor properties[] = {
DECLARE_NAPI_PROPERTY("Test", Test),
DECLARE_NAPI_PROPERTY("TestStringLength", TestStringLength),
};

NAPI_CALL(env, napi_define_properties(
Expand Down
11 changes: 7 additions & 4 deletions test/addons-napi/test_function/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,23 @@ const test_function = require(`./build/${common.buildType}/test_function`);
function func1() {
return 1;
}
assert.strictEqual(test_function.Test(func1), 1);
assert.strictEqual(test_function.TestCall(func1), 1);

function func2() {
console.log('hello world!');
return null;
}
assert.strictEqual(test_function.Test(func2), null);
assert.strictEqual(test_function.TestCall(func2), null);

function func3(input) {
return input + 1;
}
assert.strictEqual(test_function.Test(func3, 1), 2);
assert.strictEqual(test_function.TestCall(func3, 1), 2);

function func4(input) {
return func3(input);
}
assert.strictEqual(test_function.Test(func4, 1), 2);
assert.strictEqual(test_function.TestCall(func4, 1), 2);

assert.strictEqual(test_function.TestName.name, 'Name');
assert.strictEqual(test_function.TestNameShort.name, 'Name_');
23 changes: 19 additions & 4 deletions test/addons-napi/test_function/test_function.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include <node_api.h>
#include "../common.h"

napi_value Test(napi_env env, napi_callback_info info) {
napi_value TestCallFunction(napi_env env, napi_callback_info info) {
size_t argc = 10;
napi_value args[10];
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
Expand All @@ -26,10 +26,25 @@ napi_value Test(napi_env env, napi_callback_info info) {
return result;
}

void TestFunctionName(napi_env env, napi_callback_info info) {}

napi_value Init(napi_env env, napi_value exports) {
napi_value fn;
NAPI_CALL(env, napi_create_function(env, NULL, Test, NULL, &fn));
NAPI_CALL(env, napi_set_named_property(env, exports, "Test", fn));
napi_value fn1;
NAPI_CALL(env, napi_create_function(
env, NULL, -1, TestCallFunction, NULL, &fn1));

napi_value fn2;
NAPI_CALL(env, napi_create_function(
env, "Name", -1, TestFunctionName, NULL, &fn2));

napi_value fn3;
NAPI_CALL(env, napi_create_function(
env, "Name_extra", 5, TestFunctionName, NULL, &fn3));

NAPI_CALL(env, napi_set_named_property(env, exports, "TestCall", fn1));
NAPI_CALL(env, napi_set_named_property(env, exports, "TestName", fn2));
NAPI_CALL(env, napi_set_named_property(env, exports, "TestNameShort", fn3));

return exports;
}

Expand Down
2 changes: 1 addition & 1 deletion test/addons-napi/test_make_callback/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ napi_value MakeCallback(napi_env env, napi_callback_info info) {

napi_value Init(napi_env env, napi_value exports) {
napi_value fn;
NAPI_CALL(env, napi_create_function(env, NULL, MakeCallback, NULL, &fn));
NAPI_CALL(env, napi_create_function(env, NULL, -1, MakeCallback, NULL, &fn));
NAPI_CALL(env, napi_set_named_property(env, exports, "makeCallback", fn));
return exports;
}
Expand Down
2 changes: 1 addition & 1 deletion test/addons-napi/test_make_callback_recurse/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ napi_value MakeCallback(napi_env env, napi_callback_info info) {

napi_value Init(napi_env env, napi_value exports) {
napi_value fn;
NAPI_CALL(env, napi_create_function(env, NULL, MakeCallback, NULL, &fn));
NAPI_CALL(env, napi_create_function(env, NULL, -1, MakeCallback, NULL, &fn));
NAPI_CALL(env, napi_set_named_property(env, exports, "makeCallback", fn));
return exports;
}
Expand Down