node-api: store external type tags by value
Overview
A change introduced in Node 20.12 and Node 21.6 changes the semantics of tagging External values, and introduces a possible memory bug.
This pull request is responsible for the change: https://github.com/nodejs/node/pull/51149
The code in this commit stores the type tag pointer and not the 128-bit value inside. This breaks some pre-existing code that were making temporary tags. It also means that unloading the module will cause existing External objects to have a tag pointer that points... "nowhere" (use-after-free).
This violates what is stated in the N-API documentation:
A type tag is a 128-bit integer unique to the addon. Node-API provides the napi_type_tag structure for storing a type tag. [...] This creates a type-checking capability of a higher fidelity than napi_instanceof() can provide, because such type- tagging survives prototype manipulation and addon unloading/reloading.
For objects, nothing has changed since type tags are still stored in a private property (in a BigInt). So the pointer does not get stale.
This potential bug was reported here: #52387 (closed)
Patch series
The first patch fixes the issue, the second patch changes existing type tagging tests to make sure this issue does not reoccur in the future.