Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 395c56b

Browse filesBrowse files
gabrielschulhofdanielleadams
authored andcommitted
node-api: extend type-tagging to externals
Since externals behave as JavaScript objects on the JavaScript side, allow them to be type-tagged. Signed-off-by: Gabriel Schulhof <gabrielschulhof@gmail.com> PR-URL: #47141 Reviewed-By: Michael Dawson <midawson@redhat.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
1 parent 4edc1ab commit 395c56b
Copy full SHA for 395c56b

File tree

Expand file treeCollapse file tree

3 files changed

+117
-45
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

3 files changed

+117
-45
lines changed
Open diff view settings
Collapse file

‎doc/api/n-api.md‎

Copy file name to clipboardExpand all lines: doc/api/n-api.md
+17-14Lines changed: 17 additions & 14 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -733,13 +733,13 @@ napiVersion: 8
733733
-->
734734

735735
A 128-bit value stored as two unsigned 64-bit integers. It serves as a UUID
736-
with which JavaScript objects can be "tagged" in order to ensure that they are
737-
of a certain type. This is a stronger check than [`napi_instanceof`][], because
738-
the latter can report a false positive if the object's prototype has been
739-
manipulated. Type-tagging is most useful in conjunction with [`napi_wrap`][]
740-
because it ensures that the pointer retrieved from a wrapped object can be
741-
safely cast to the native type corresponding to the type tag that had been
742-
previously applied to the JavaScript object.
736+
with which JavaScript objects or [externals][] can be "tagged" in order to
737+
ensure that they are of a certain type. This is a stronger check than
738+
[`napi_instanceof`][], because the latter can report a false positive if the
739+
object's prototype has been manipulated. Type-tagging is most useful in
740+
conjunction with [`napi_wrap`][] because it ensures that the pointer retrieved
741+
from a wrapped object can be safely cast to the native type corresponding to the
742+
type tag that had been previously applied to the JavaScript object.
743743

744744
```c
745745
typedef struct {
@@ -4965,7 +4965,7 @@ To this end, Node-API provides type-tagging capabilities.
49654965

49664966
A type tag is a 128-bit integer unique to the addon. Node-API provides the
49674967
`napi_type_tag` structure for storing a type tag. When such a value is passed
4968-
along with a JavaScript object stored in a `napi_value` to
4968+
along with a JavaScript object or [external][] stored in a `napi_value` to
49694969
`napi_type_tag_object()`, the JavaScript object will be "marked" with the
49704970
type tag. The "mark" is invisible on the JavaScript side. When a JavaScript
49714971
object arrives into a native binding, `napi_check_object_type_tag()` can be used
@@ -5251,15 +5251,15 @@ napi_status napi_type_tag_object(napi_env env,
52515251
```
52525252

52535253
* `[in] env`: The environment that the API is invoked under.
5254-
* `[in] js_object`: The JavaScript object to be marked.
5254+
* `[in] js_object`: The JavaScript object or [external][] to be marked.
52555255
* `[in] type_tag`: The tag with which the object is to be marked.
52565256

52575257
Returns `napi_ok` if the API succeeded.
52585258

5259-
Associates the value of the `type_tag` pointer with the JavaScript object.
5260-
`napi_check_object_type_tag()` can then be used to compare the tag that was
5261-
attached to the object with one owned by the addon to ensure that the object
5262-
has the right type.
5259+
Associates the value of the `type_tag` pointer with the JavaScript object or
5260+
[external][]. `napi_check_object_type_tag()` can then be used to compare the tag
5261+
that was attached to the object with one owned by the addon to ensure that the
5262+
object has the right type.
52635263

52645264
If the object already has an associated type tag, this API will return
52655265
`napi_invalid_arg`.
@@ -5281,7 +5281,8 @@ napi_status napi_check_object_type_tag(napi_env env,
52815281
```
52825282

52835283
* `[in] env`: The environment that the API is invoked under.
5284-
* `[in] js_object`: The JavaScript object whose type tag to examine.
5284+
* `[in] js_object`: The JavaScript object or [external][] whose type tag to
5285+
examine.
52855286
* `[in] type_tag`: The tag with which to compare any tag found on the object.
52865287
* `[out] result`: Whether the type tag given matched the type tag on the
52875288
object. `false` is also returned if no type tag was found on the object.
@@ -6451,6 +6452,8 @@ the add-on's file name during loading.
64516452
[async_hooks `type`]: async_hooks.md#type
64526453
[context-aware addons]: addons.md#context-aware-addons
64536454
[docs]: https://github.com/nodejs/node-addon-api#api-documentation
6455+
[external]: #napi_create_external
6456+
[externals]: #napi_create_external
64546457
[global scope]: globals.md
64556458
[gyp-next]: https://github.com/nodejs/gyp-next
64566459
[module scope]: modules.md#the-module-scope
Collapse file

‎test/js-native-api/test_object/test.js‎

Copy file name to clipboardExpand all lines: test/js-native-api/test_object/test.js
+23Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,12 +165,26 @@ assert.strictEqual(newObject.test_string, 'test string');
165165
const obj2 = test_object.TypeTaggedInstance(1);
166166
const obj3 = test_object.TypeTaggedInstance(2);
167167
const obj4 = test_object.TypeTaggedInstance(3);
168+
const external = test_object.TypeTaggedExternal(2);
169+
const plainExternal = test_object.PlainExternal();
170+
171+
// Verify that we do not allow type tag indices greater than the largest
172+
// available index.
173+
assert.throws(() => test_object.TypeTaggedInstance(39), {
174+
name: 'RangeError',
175+
message: 'Invalid type index',
176+
});
177+
assert.throws(() => test_object.TypeTaggedExternal(39), {
178+
name: 'RangeError',
179+
message: 'Invalid type index',
180+
});
168181

169182
// Verify that type tags are correctly accepted.
170183
assert.strictEqual(test_object.CheckTypeTag(0, obj1), true);
171184
assert.strictEqual(test_object.CheckTypeTag(1, obj2), true);
172185
assert.strictEqual(test_object.CheckTypeTag(2, obj3), true);
173186
assert.strictEqual(test_object.CheckTypeTag(3, obj4), true);
187+
assert.strictEqual(test_object.CheckTypeTag(2, external), true);
174188

175189
// Verify that wrongly tagged objects are rejected.
176190
assert.strictEqual(test_object.CheckTypeTag(0, obj2), false);
@@ -180,10 +194,19 @@ assert.strictEqual(newObject.test_string, 'test string');
180194
assert.strictEqual(test_object.CheckTypeTag(2, obj4), false);
181195
assert.strictEqual(test_object.CheckTypeTag(3, obj3), false);
182196
assert.strictEqual(test_object.CheckTypeTag(4, obj3), false);
197+
assert.strictEqual(test_object.CheckTypeTag(0, external), false);
198+
assert.strictEqual(test_object.CheckTypeTag(1, external), false);
199+
assert.strictEqual(test_object.CheckTypeTag(3, external), false);
200+
assert.strictEqual(test_object.CheckTypeTag(4, external), false);
183201

184202
// Verify that untagged objects are rejected.
185203
assert.strictEqual(test_object.CheckTypeTag(0, {}), false);
186204
assert.strictEqual(test_object.CheckTypeTag(1, {}), false);
205+
assert.strictEqual(test_object.CheckTypeTag(0, plainExternal), false);
206+
assert.strictEqual(test_object.CheckTypeTag(1, plainExternal), false);
207+
assert.strictEqual(test_object.CheckTypeTag(2, plainExternal), false);
208+
assert.strictEqual(test_object.CheckTypeTag(3, plainExternal), false);
209+
assert.strictEqual(test_object.CheckTypeTag(4, plainExternal), false);
187210
}
188211

189212
{
Collapse file

‎test/js-native-api/test_object/test_object.c‎

Copy file name to clipboardExpand all lines: test/js-native-api/test_object/test_object.c
+77-31Lines changed: 77 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -605,13 +605,23 @@ static napi_value TestSeal(napi_env env,
605605
}
606606

607607
// We create two type tags. They are basically 128-bit UUIDs.
608-
static const napi_type_tag type_tags[5] = {
609-
{ 0xdaf987b3cc62481a, 0xb745b0497f299531 },
610-
{ 0xbb7936c374084d9b, 0xa9548d0762eeedb9 },
611-
{ 0xa5ed9ce2e4c00c38, 0 },
612-
{ 0, 0 },
613-
{ 0xa5ed9ce2e4c00c38, 0xdaf987b3cc62481a },
608+
#define TYPE_TAG_COUNT 5
609+
static const napi_type_tag type_tags[TYPE_TAG_COUNT] = {
610+
{0xdaf987b3cc62481a, 0xb745b0497f299531},
611+
{0xbb7936c374084d9b, 0xa9548d0762eeedb9},
612+
{0xa5ed9ce2e4c00c38, 0},
613+
{0, 0},
614+
{0xa5ed9ce2e4c00c38, 0xdaf987b3cc62481a},
614615
};
616+
#define VALIDATE_TYPE_INDEX(env, type_index) \
617+
do { \
618+
if ((type_index) >= TYPE_TAG_COUNT) { \
619+
NODE_API_CALL((env), \
620+
napi_throw_range_error((env), \
621+
"NODE_API_TEST_INVALID_TYPE_INDEX", \
622+
"Invalid type index")); \
623+
} \
624+
} while (0)
615625

616626
static napi_value
617627
TypeTaggedInstance(napi_env env, napi_callback_info info) {
@@ -621,12 +631,42 @@ TypeTaggedInstance(napi_env env, napi_callback_info info) {
621631

622632
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, &which_type, NULL, NULL));
623633
NODE_API_CALL(env, napi_get_value_uint32(env, which_type, &type_index));
634+
VALIDATE_TYPE_INDEX(env, type_index);
624635
NODE_API_CALL(env, napi_create_object(env, &instance));
625636
NODE_API_CALL(env, napi_type_tag_object(env, instance, &type_tags[type_index]));
626637

627638
return instance;
628639
}
629640

641+
// V8 will not allowe us to construct an external with a NULL data value.
642+
#define IN_LIEU_OF_NULL ((void*)0x1)
643+
644+
static napi_value PlainExternal(napi_env env, napi_callback_info info) {
645+
napi_value instance;
646+
647+
NODE_API_CALL(
648+
env, napi_create_external(env, IN_LIEU_OF_NULL, NULL, NULL, &instance));
649+
650+
return instance;
651+
}
652+
653+
static napi_value TypeTaggedExternal(napi_env env, napi_callback_info info) {
654+
size_t argc = 1;
655+
uint32_t type_index;
656+
napi_value instance, which_type;
657+
658+
NODE_API_CALL(env,
659+
napi_get_cb_info(env, info, &argc, &which_type, NULL, NULL));
660+
NODE_API_CALL(env, napi_get_value_uint32(env, which_type, &type_index));
661+
VALIDATE_TYPE_INDEX(env, type_index);
662+
NODE_API_CALL(
663+
env, napi_create_external(env, IN_LIEU_OF_NULL, NULL, NULL, &instance));
664+
NODE_API_CALL(env,
665+
napi_type_tag_object(env, instance, &type_tags[type_index]));
666+
667+
return instance;
668+
}
669+
630670
static napi_value
631671
CheckTypeTag(napi_env env, napi_callback_info info) {
632672
size_t argc = 2;
@@ -636,6 +676,7 @@ CheckTypeTag(napi_env env, napi_callback_info info) {
636676

637677
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
638678
NODE_API_CALL(env, napi_get_value_uint32(env, argv[0], &type_index));
679+
VALIDATE_TYPE_INDEX(env, type_index);
639680
NODE_API_CALL(env, napi_check_object_type_tag(env,
640681
argv[1],
641682
&type_tags[type_index],
@@ -648,31 +689,36 @@ CheckTypeTag(napi_env env, napi_callback_info info) {
648689
EXTERN_C_START
649690
napi_value Init(napi_env env, napi_value exports) {
650691
napi_property_descriptor descriptors[] = {
651-
DECLARE_NODE_API_PROPERTY("Get", Get),
652-
DECLARE_NODE_API_PROPERTY("GetNamed", GetNamed),
653-
DECLARE_NODE_API_PROPERTY("GetPropertyNames", GetPropertyNames),
654-
DECLARE_NODE_API_PROPERTY("GetSymbolNames", GetSymbolNames),
655-
DECLARE_NODE_API_PROPERTY("GetEnumerableWritableNames", GetEnumerableWritableNames),
656-
DECLARE_NODE_API_PROPERTY("GetOwnWritableNames", GetOwnWritableNames),
657-
DECLARE_NODE_API_PROPERTY("GetEnumerableConfigurableNames", GetEnumerableConfigurableNames),
658-
DECLARE_NODE_API_PROPERTY("GetOwnConfigurableNames", GetOwnConfigurableNames),
659-
DECLARE_NODE_API_PROPERTY("Set", Set),
660-
DECLARE_NODE_API_PROPERTY("SetNamed", SetNamed),
661-
DECLARE_NODE_API_PROPERTY("Has", Has),
662-
DECLARE_NODE_API_PROPERTY("HasNamed", HasNamed),
663-
DECLARE_NODE_API_PROPERTY("HasOwn", HasOwn),
664-
DECLARE_NODE_API_PROPERTY("Delete", Delete),
665-
DECLARE_NODE_API_PROPERTY("New", New),
666-
DECLARE_NODE_API_PROPERTY("Inflate", Inflate),
667-
DECLARE_NODE_API_PROPERTY("Wrap", Wrap),
668-
DECLARE_NODE_API_PROPERTY("Unwrap", Unwrap),
669-
DECLARE_NODE_API_PROPERTY("TestSetProperty", TestSetProperty),
670-
DECLARE_NODE_API_PROPERTY("TestHasProperty", TestHasProperty),
671-
DECLARE_NODE_API_PROPERTY("TypeTaggedInstance", TypeTaggedInstance),
672-
DECLARE_NODE_API_PROPERTY("CheckTypeTag", CheckTypeTag),
673-
DECLARE_NODE_API_PROPERTY("TestGetProperty", TestGetProperty),
674-
DECLARE_NODE_API_PROPERTY("TestFreeze", TestFreeze),
675-
DECLARE_NODE_API_PROPERTY("TestSeal", TestSeal),
692+
DECLARE_NODE_API_PROPERTY("Get", Get),
693+
DECLARE_NODE_API_PROPERTY("GetNamed", GetNamed),
694+
DECLARE_NODE_API_PROPERTY("GetPropertyNames", GetPropertyNames),
695+
DECLARE_NODE_API_PROPERTY("GetSymbolNames", GetSymbolNames),
696+
DECLARE_NODE_API_PROPERTY("GetEnumerableWritableNames",
697+
GetEnumerableWritableNames),
698+
DECLARE_NODE_API_PROPERTY("GetOwnWritableNames", GetOwnWritableNames),
699+
DECLARE_NODE_API_PROPERTY("GetEnumerableConfigurableNames",
700+
GetEnumerableConfigurableNames),
701+
DECLARE_NODE_API_PROPERTY("GetOwnConfigurableNames",
702+
GetOwnConfigurableNames),
703+
DECLARE_NODE_API_PROPERTY("Set", Set),
704+
DECLARE_NODE_API_PROPERTY("SetNamed", SetNamed),
705+
DECLARE_NODE_API_PROPERTY("Has", Has),
706+
DECLARE_NODE_API_PROPERTY("HasNamed", HasNamed),
707+
DECLARE_NODE_API_PROPERTY("HasOwn", HasOwn),
708+
DECLARE_NODE_API_PROPERTY("Delete", Delete),
709+
DECLARE_NODE_API_PROPERTY("New", New),
710+
DECLARE_NODE_API_PROPERTY("Inflate", Inflate),
711+
DECLARE_NODE_API_PROPERTY("Wrap", Wrap),
712+
DECLARE_NODE_API_PROPERTY("Unwrap", Unwrap),
713+
DECLARE_NODE_API_PROPERTY("TestSetProperty", TestSetProperty),
714+
DECLARE_NODE_API_PROPERTY("TestHasProperty", TestHasProperty),
715+
DECLARE_NODE_API_PROPERTY("TypeTaggedInstance", TypeTaggedInstance),
716+
DECLARE_NODE_API_PROPERTY("TypeTaggedExternal", TypeTaggedExternal),
717+
DECLARE_NODE_API_PROPERTY("PlainExternal", PlainExternal),
718+
DECLARE_NODE_API_PROPERTY("CheckTypeTag", CheckTypeTag),
719+
DECLARE_NODE_API_PROPERTY("TestGetProperty", TestGetProperty),
720+
DECLARE_NODE_API_PROPERTY("TestFreeze", TestFreeze),
721+
DECLARE_NODE_API_PROPERTY("TestSeal", TestSeal),
676722
};
677723

678724
init_test_null(env, exports);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.