GeezerVison is showing github.com — node-api: extend type-tagging to externals · nodejs/node@77f7200
File treeExpand file treeCollapse file tree Open diff view settings test/js-native-api/test_object
Expand file treeCollapse file tree Open diff view settings Collapse file 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 number | Diff line number | Diff line change |
|---|
@@ -733,13 +733,13 @@ napiVersion: 8 | 733 | 733 | --> | 734 | 734 |
| 735 | 735 | 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. | 743 | 743 |
| 744 | 744 | ```c | 745 | 745 | typedef struct { | @@ -4967,7 +4967,7 @@ To this end, Node-API provides type-tagging capabilities. | 4967 | 4967 |
| 4968 | 4968 | A type tag is a 128-bit integer unique to the addon. Node-API provides the | 4969 | 4969 | `napi_type_tag` structure for storing a type tag. When such a value is passed | 4970 | | -along with a JavaScript object stored in a `napi_value` to | | 4970 | +along with a JavaScript object or [external][] stored in a `napi_value` to | 4971 | 4971 | `napi_type_tag_object()`, the JavaScript object will be "marked" with the | 4972 | 4972 | type tag. The "mark" is invisible on the JavaScript side. When a JavaScript | 4973 | 4973 | object arrives into a native binding, `napi_check_object_type_tag()` can be used | @@ -5253,15 +5253,15 @@ napi_status napi_type_tag_object(napi_env env, | 5253 | 5253 | ``` | 5254 | 5254 |
| 5255 | 5255 | * `[in] env`: The environment that the API is invoked under. | 5256 | | -* `[in] js_object`: The JavaScript object to be marked. | | 5256 | +* `[in] js_object`: The JavaScript object or [external][] to be marked. | 5257 | 5257 | * `[in] type_tag`: The tag with which the object is to be marked. | 5258 | 5258 |
| 5259 | 5259 | Returns `napi_ok` if the API succeeded. | 5260 | 5260 |
| 5261 | | -Associates the value of the `type_tag` pointer with the JavaScript object. | 5262 | | -`napi_check_object_type_tag()` can then be used to compare the tag that was | 5263 | | -attached to the object with one owned by the addon to ensure that the object | 5264 | | -has the right type. | | 5261 | +Associates the value of the `type_tag` pointer with the JavaScript object or | | 5262 | +[external][]. `napi_check_object_type_tag()` can then be used to compare the tag | | 5263 | +that was attached to the object with one owned by the addon to ensure that the | | 5264 | +object has the right type. | 5265 | 5265 |
| 5266 | 5266 | If the object already has an associated type tag, this API will return | 5267 | 5267 | `napi_invalid_arg`. | @@ -5283,7 +5283,8 @@ napi_status napi_check_object_type_tag(napi_env env, | 5283 | 5283 | ``` | 5284 | 5284 |
| 5285 | 5285 | * `[in] env`: The environment that the API is invoked under. | 5286 | | -* `[in] js_object`: The JavaScript object whose type tag to examine. | | 5286 | +* `[in] js_object`: The JavaScript object or [external][] whose type tag to | | 5287 | + examine. | 5287 | 5288 | * `[in] type_tag`: The tag with which to compare any tag found on the object. | 5288 | 5289 | * `[out] result`: Whether the type tag given matched the type tag on the | 5289 | 5290 | object. `false` is also returned if no type tag was found on the object. | @@ -6453,6 +6454,8 @@ the add-on's file name during loading. | 6453 | 6454 | [async_hooks `type`]: async_hooks.md#type | 6454 | 6455 | [context-aware addons]: addons.md#context-aware-addons | 6455 | 6456 | [docs]: https://github.com/nodejs/node-addon-api#api-documentation | | 6457 | +[external]: #napi_create_external | | 6458 | +[externals]: #napi_create_external | 6456 | 6459 | [global scope]: globals.md | 6457 | 6460 | [gyp-next]: https://github.com/nodejs/gyp-next | 6458 | 6461 | [module scope]: modules.md#the-module-scope | |
Collapse file Copy file name to clipboardExpand all lines: test/js-native-api/test_object/test.js +23Lines changed: 23 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -165,12 +165,26 @@ assert.strictEqual(newObject.test_string, 'test string'); | 165 | 165 | const obj2 = test_object.TypeTaggedInstance(1); | 166 | 166 | const obj3 = test_object.TypeTaggedInstance(2); | 167 | 167 | 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 | + }); | 168 | 181 |
| 169 | 182 | // Verify that type tags are correctly accepted. | 170 | 183 | assert.strictEqual(test_object.CheckTypeTag(0, obj1), true); | 171 | 184 | assert.strictEqual(test_object.CheckTypeTag(1, obj2), true); | 172 | 185 | assert.strictEqual(test_object.CheckTypeTag(2, obj3), true); | 173 | 186 | assert.strictEqual(test_object.CheckTypeTag(3, obj4), true); | | 187 | + assert.strictEqual(test_object.CheckTypeTag(2, external), true); | 174 | 188 |
| 175 | 189 | // Verify that wrongly tagged objects are rejected. | 176 | 190 | assert.strictEqual(test_object.CheckTypeTag(0, obj2), false); | @@ -180,10 +194,19 @@ assert.strictEqual(newObject.test_string, 'test string'); | 180 | 194 | assert.strictEqual(test_object.CheckTypeTag(2, obj4), false); | 181 | 195 | assert.strictEqual(test_object.CheckTypeTag(3, obj3), false); | 182 | 196 | 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); | 183 | 201 |
| 184 | 202 | // Verify that untagged objects are rejected. | 185 | 203 | assert.strictEqual(test_object.CheckTypeTag(0, {}), false); | 186 | 204 | 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); | 187 | 210 | } | 188 | 211 |
| 189 | 212 | { | |
Collapse file 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 number | Diff line number | Diff line change |
|---|
@@ -605,13 +605,23 @@ static napi_value TestSeal(napi_env env, | 605 | 605 | } | 606 | 606 |
| 607 | 607 | // 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}, | 614 | 615 | }; | | 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) | 615 | 625 |
| 616 | 626 | static napi_value | 617 | 627 | TypeTaggedInstance(napi_env env, napi_callback_info info) { | @@ -621,12 +631,42 @@ TypeTaggedInstance(napi_env env, napi_callback_info info) { | 621 | 631 |
| 622 | 632 | NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, &which_type, NULL, NULL)); | 623 | 633 | NODE_API_CALL(env, napi_get_value_uint32(env, which_type, &type_index)); | | 634 | + VALIDATE_TYPE_INDEX(env, type_index); | 624 | 635 | NODE_API_CALL(env, napi_create_object(env, &instance)); | 625 | 636 | NODE_API_CALL(env, napi_type_tag_object(env, instance, &type_tags[type_index])); | 626 | 637 |
| 627 | 638 | return instance; | 628 | 639 | } | 629 | 640 |
| | 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 | + | 630 | 670 | static napi_value | 631 | 671 | CheckTypeTag(napi_env env, napi_callback_info info) { | 632 | 672 | size_t argc = 2; | @@ -636,6 +676,7 @@ CheckTypeTag(napi_env env, napi_callback_info info) { | 636 | 676 |
| 637 | 677 | NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); | 638 | 678 | NODE_API_CALL(env, napi_get_value_uint32(env, argv[0], &type_index)); | | 679 | + VALIDATE_TYPE_INDEX(env, type_index); | 639 | 680 | NODE_API_CALL(env, napi_check_object_type_tag(env, | 640 | 681 | argv[1], | 641 | 682 | &type_tags[type_index], | @@ -648,31 +689,36 @@ CheckTypeTag(napi_env env, napi_callback_info info) { | 648 | 689 | EXTERN_C_START | 649 | 690 | napi_value Init(napi_env env, napi_value exports) { | 650 | 691 | 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), | 676 | 722 | }; | 677 | 723 |
| 678 | 724 | init_test_null(env, exports); | |
|