The term "native module" dates back to some of the oldest code
in the code base. Within the context of Node.js core it usually
refers to modules that are native to Node.js (e.g. fs, http),
but it can cause confusion for people who don't work on this
part of the code base, as "native module" can also refer to
native addons - which is even the case in some of the API
docs and error messages.
This patch tries to make the usage of these terms more consistent.
Now within the context of Node.js core:
- JavaScript scripts that are built-in to Node.js are now referred
to as "built-in(s)". If they are available as modules,
they can also be referred to as "built-in module(s)".
- Dynamically-linked shared objects that are loaded into
the Node.js processes are referred to as "addons".
We will try to avoid using the term "native modules" because it could
be ambiguous.
Changes in this patch:
File names:
- node_native_module.h -> node_builtins.h,
- node_native_module.cc -> node_builtins.cc
C++ binding names:
- `native_module` -> `builtins`
`node::Environment`:
- `native_modules_without_cache` -> `builtins_without_cache`
- `native_modules_with_cache` -> `builtins_with_cache`
- `native_modules_in_snapshot` -> `builtins_in_cache`
- `native_module_require` -> `builtin_module_require`
`node::EnvSerializeInfo`:
- `native_modules` -> `builtins
`node::native_module::NativeModuleLoader`:
- `native_module` namespace -> `builtins` namespace
- `NativeModuleLoader` -> `BuiltinLoader`
- `NativeModuleRecordMap` -> `BuiltinSourceMap`
- `NativeModuleCacheMap` -> `BuiltinCodeCacheMap`
- `ModuleIds` -> `BuiltinIds`
- `ModuleCategories` -> `BuiltinCategories`
- `LoadBuiltinModuleSource` -> `LoadBuiltinSource`
`loader.js`:
- `NativeModule` -> `BuiltinModule` (the `NativeModule` name used in
`process.moduleLoadList` is kept for compatibility)
And other clarifications in the documentation and comments.
PR-URL: https://github.com/nodejs/node/pull/44135
Fixes: https://github.com/nodejs/node/issues/44036
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Michael Dawson <midawson@redhat.com>
Reviewed-By: Richard Lau <rlau@redhat.com>
Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
Reviewed-By: Jan Krems <jan.krems@gmail.com>
Currently test/node-api/test_fatal/test_threads.js fails for a Debug
build with the following error:
1: 0x101e3f8 node::DumpBacktrace(_IO_FILE*) [/node/out/Debug/node]
2: 0x11c31ed [/node/out/Debug/node]
3: 0x11c320d [/node/out/Debug/node]
4: 0x2ba4448 V8_Fatal(char const*, int, char const*, ...) [/node/out/Debug/node]
5: 0x2ba4473 [/node/out/Debug/node]
6: 0x139e049 v8::internal::Isolate::Current() [/node/out/Debug/node]
7: 0x11025ee node::OnFatalError(char const*, char const*) [/node/out/Debug/node]
8: 0x1102564 node::FatalError(char const*, char const*) [/node/out/Debug/node]
9: 0x10add1d napi_open_callback_scope [/node/out/Debug/node]
10: 0x7f05664211dc [/node/test/node-api/test_fatal/build/Debug/test_fatal.node]
11: 0x7f056608e4e2 [/usr/lib64/libpthread.so.0]
12: 0x7f0565fbd6c3 clone [/usr/lib64/libc.so.6]
node:assert:412
throw err;
^
AssertionError [ERR_ASSERTION]: The expression evaluated to a falsy value:
assert.ok(p.status === 134 || p.signal === 'SIGABRT')
at Object.<anonymous> (/node/test/node-api/test_fatal/test_threads.js:21:8)
at Module._compile (node:internal/modules/cjs/loader:1109:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1138:10)
at Module.load (node:internal/modules/cjs/loader:989:32)
at Function.Module._load (node:internal/modules/cjs/loader:829:14)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:79:12)
at node:internal/main/run_main_module:17:47 {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: false,
expected: true,
operator: '=='
}
This is caused by a call to Isolate::GetCurrent() when the calling
thread has not initialized V8. We are working suggestion to add a method
to V8 which allows a check/get without any checks but in the mean time
this change should allow debug builds to pass the test suit.
PR-URL: https://github.com/nodejs/node/pull/38805
Refs: https://chromium-review.googlesource.com/c/v8/v8/+/2910630
Reviewed-By: Michael Dawson <midawson@redhat.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Invoke threadsafe_function during the same tick and avoid marshalling
costs between threads and/or churning event loop if either:
1. There's a queued call already
2. `Push()` is called while the main thread was running
threadsafe_function
PR-URL: https://github.com/nodejs/node/pull/38506
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Unlike JS-only modules, native add-ons are always associated with a
dynamic shared object from which they are loaded. Being able to
retrieve its absolute path is important to native-only add-ons, i.e.
add-ons that are not themselves being loaded from a JS-only module
located in the same package as the native add-on itself.
Currently, the file name is obtained at environment construction time
from the JS `module.filename`. Nevertheless, the presence of `module`
is not required, because the file name could also be passed in via a
private property added onto `exports` from the `process.dlopen`
binding.
As an attempt at future-proofing, the file name is provided as a URL,
i.e. prefixed with the `file://` protocol.
Fixes: https://github.com/nodejs/node-addon-api/issues/449
PR-URL: https://github.com/nodejs/node/pull/37195
Co-authored-by: Michael Dawson <mdawson@devrus.com>
Reviewed-By: Michael Dawson <midawson@redhat.com>
Currently, a reference is being unlinked from the list of references
tracked by the environment when `v8impl::Reference::Delete` is called.
This causes a leak when deletion must be deferred because the finalizer
hasn't yet run, but the finalizer does not run because environment
teardown is in progress, and so no more gc runs will happen, and the
`FinalizeAll` run that happens during environment teardown does not
catch the reference because it's no longer in the list. The test below
will fail when running with ASAN:
```
./node ./test/node-api/test_worker_terminate_finalization/test.js
```
OTOH if, to address the above leak, we make a special case to not
unlink a reference during environment teardown, we run into a
situation where the reference gets deleted by
`v8impl::Reference::Delete` but does not get unlinked because it's
environment teardown time. This leaves a stale pointer in the linked
list which will result in a use-after-free in `FinalizeAll` during
environment teardown. The test below will fail if we make the above
change:
```
./node -e "require('./test/node-api/test_instance_data/build/Release/test_ref_then_set.node');"
```
Thus, we unlink a reference precisely when we destroy it – in its
destructor.
Refs: https://github.com/nodejs/node/issues/34731
Refs: https://github.com/nodejs/node/pull/34839
Refs: https://github.com/nodejs/node/issues/35620
Refs: https://github.com/nodejs/node/issues/35777
Fixes: https://github.com/nodejs/node/issues/35778
Signed-off-by: Gabriel Schulhof <gabriel.schulhof@intel.com>
PR-URL: https://github.com/nodejs/node/pull/35933
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Michael Dawson <midawson@redhat.com>
Reviewed-By: Zeyu Yang <himself65@outlook.com>
* Prefix functions with `static` to make them local
* Remove anonymous namespaces
* `nullptr` -> `NULL`
* .cc -> .c and update binding.gyp
* `static_cast<x>()` -> `(x)()`
* Replace `new`/`delete` with `malloc()`/`free()`
(only in test_callback_scope)
* Move lambda out and convert to local function
(only in test_callback_scope)
* Remove superfluous `#include <vector>`
(only in test_callback_scope_recurse)
Some tests are best left as C++.
```bash
ls -l test/{node-api,js-native-api}/*/*.cc
```
for those remaining as C++ tests.
Signed-off-by: Gabriel Schulhof <gabriel.schulhof@intel.com>
PR-URL: https://github.com/nodejs/node/pull/34615
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de>
Release `Buffer` and `ArrayBuffer` instances that were created through
our addon APIs and have finalizers attached to them only after V8 has
called the deleter callback passed to the `BackingStore`, instead of
relying on our own GC callback(s).
This fixes the following race condition:
1. Addon code allocates pointer P via `malloc`.
2. P is passed into `napi_create_external_buffer` with a finalization
callback which calls `free(P)`. P is inserted into V8’s global array
buffer table for tracking.
3. The finalization callback is executed on GC. P is freed and returned
to the allocator. P is not yet removed from V8’s global array
buffer table. (!)
4. Addon code attempts to allocate memory once again. The allocator
returns P, as it is now available.
5. P is passed into `napi_create_external_buffer`. P still has not been
removed from the v8 global array buffer table.
6. The world ends with `Check failed: result.second`.
Since our API contract is to call the finalizer on the JS thread on
which the `ArrayBuffer` was created, but V8 may call the `BackingStore`
deleter callback on another thread, fixing this requires posting
a task back to the JS thread.
Refs: https://github.com/nodejs/node/issues/32463#issuecomment-625877175
Fixes: https://github.com/nodejs/node/issues/32463
PR-URL: https://github.com/nodejs/node/pull/33321
Reviewed-By: James M Snell <jasnell@gmail.com>
Instance data associated with a `napi_env` is no longer stored on the
env itself but is instead rendered as a reference. Since
`v8impl::Reference` is tied to a JS object, this modification factors
out the `v8impl::Reference` refcounting and the deletion process into
a base class for `v8impl::Reference`, called `v8impl::RefBase`. The
instance data is then stored as a `v8impl::RefBase`, along with other
references, preventing a segfault that arises from the fact that, up
until now, upon `napi_env` destruction, the instance data was freed
after all references had already been forcefully freed. If the addon
freed a reference during the `napi_set_instance_data` finalizer
callback, such a reference had already been freed during environment
teardown, causing a double free.
Re: https://github.com/nodejs/node-addon-api/pull/663
PR-URL: https://github.com/nodejs/node/pull/31638
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: David Carlier <devnexen@gmail.com>