summaryrefslogtreecommitdiff
path: root/test_napi
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2023-05-26 06:40:17 +0200
committerGitHub <noreply@github.com>2023-05-26 10:10:17 +0530
commit512d5337c480a2a2704881d3fe1c40b6e0445cf0 (patch)
tree99b03358883223a69f48b2d0e5b9387f3abae517 /test_napi
parent7ae55e75d812edc93251357465f8d49fc2fb5d26 (diff)
fix(napi): clear currently registering module slot (#19249)
This commit fixes problem with loading N-API modules that use the "old" way of registration (using "napi_module_register" API). The slot was not cleared after loading modules, causing subsequent calls that use the new way of registration (using "napi_register_module_v1" API) to try and load the previous module. Ref https://github.com/denoland/deno/issues/16460 --------- Co-authored-by: Divy Srivastava <dj.srivastava23@gmail.com>
Diffstat (limited to 'test_napi')
-rw-r--r--test_napi/.gitignore5
-rw-r--r--test_napi/common.js6
-rw-r--r--test_napi/init_test.js14
-rw-r--r--test_napi/module.c68
-rw-r--r--test_napi/tests/napi_tests.rs29
5 files changed, 119 insertions, 3 deletions
diff --git a/test_napi/.gitignore b/test_napi/.gitignore
index 6fdcc4a66..54de1ef34 100644
--- a/test_napi/.gitignore
+++ b/test_napi/.gitignore
@@ -1,4 +1,7 @@
package-lock.json
# Test generated artifacts
-.swc \ No newline at end of file
+.swc
+*.dylib
+*.so
+*.dll
diff --git a/test_napi/common.js b/test_napi/common.js
index 09378918f..ce9b2544b 100644
--- a/test_napi/common.js
+++ b/test_napi/common.js
@@ -9,17 +9,19 @@ export {
export { fromFileUrl } from "../test_util/std/path/mod.ts";
const targetDir = Deno.execPath().replace(/[^\/\\]+$/, "");
-const [libPrefix, libSuffix] = {
+export const [libPrefix, libSuffix] = {
darwin: ["lib", "dylib"],
linux: ["lib", "so"],
windows: ["", "dll"],
}[Deno.build.os];
+const ops = Deno[Deno.internal].core.ops;
+
export function loadTestLibrary() {
const specifier = `${targetDir}/${libPrefix}test_napi.${libSuffix}`;
// Internal, used in ext/node
- return Deno[Deno.internal].core.ops.op_napi_open(specifier, {
+ return ops.op_napi_open(specifier, {
Buffer: {},
});
}
diff --git a/test_napi/init_test.js b/test_napi/init_test.js
new file mode 100644
index 000000000..633fdbb61
--- /dev/null
+++ b/test_napi/init_test.js
@@ -0,0 +1,14 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+
+import { assert, libSuffix } from "./common.js";
+
+const ops = Deno[Deno.internal].core.ops;
+
+Deno.test("ctr initialization (napi_module_register)", {
+ ignore: Deno.build.os == "windows",
+}, function () {
+ const path = new URL(`./module.${libSuffix}`, import.meta.url).pathname;
+ const obj = ops.op_napi_open(path, {});
+ assert(obj != null);
+ assert(typeof obj === "object");
+});
diff --git a/test_napi/module.c b/test_napi/module.c
new file mode 100644
index 000000000..4548aa37f
--- /dev/null
+++ b/test_napi/module.c
@@ -0,0 +1,68 @@
+typedef struct napi_module {
+ int nm_version;
+ unsigned int nm_flags;
+ const char* nm_filename;
+ void* nm_register_func;
+ const char* nm_modname;
+ void* nm_priv;
+ void* reserved[4];
+} napi_module;
+
+#ifdef _WIN32
+#define NAPI_EXTERN __declspec(dllexport)
+#define NAPI_CDECL __cdecl
+#else
+#define NAPI_EXTERN __attribute__((visibility("default")))
+#define NAPI_CDECL
+#endif
+
+NAPI_EXTERN void NAPI_CDECL
+napi_module_register(napi_module* mod);
+
+#if defined(_MSC_VER)
+#if defined(__cplusplus)
+#define NAPI_C_CTOR(fn) \
+ static void NAPI_CDECL fn(void); \
+ namespace { \
+ struct fn##_ { \
+ fn##_() { fn(); } \
+ } fn##_v_; \
+ } \
+ static void NAPI_CDECL fn(void)
+#else // !defined(__cplusplus)
+#pragma section(".CRT$XCU", read)
+// The NAPI_C_CTOR macro defines a function fn that is called during CRT
+// initialization.
+// C does not support dynamic initialization of static variables and this code
+// simulates C++ behavior. Exporting the function pointer prevents it from being
+// optimized. See for details:
+// https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-initialization?view=msvc-170
+#define NAPI_C_CTOR(fn) \
+ static void NAPI_CDECL fn(void); \
+ __declspec(dllexport, allocate(".CRT$XCU")) void(NAPI_CDECL * fn##_)(void) = \
+ fn; \
+ static void NAPI_CDECL fn(void)
+#endif // defined(__cplusplus)
+#else
+#define NAPI_C_CTOR(fn) \
+ static void fn(void) __attribute__((constructor)); \
+ static void fn(void)
+#endif
+
+#define NAPI_MODULE_TEST(modname, regfunc) \
+ static napi_module _module = { \
+ 1, \
+ 0, \
+ __FILE__, \
+ regfunc, \
+ #modname, \
+ 0, \
+ {0}, \
+ }; \
+ NAPI_C_CTOR(_register_##modname) { napi_module_register(&_module); } \
+
+void* init(void* env __attribute__((unused)), void* exports) {
+ return exports;
+}
+
+NAPI_MODULE_TEST(TEST_NAPI_MODULE_NAME, init)
diff --git a/test_napi/tests/napi_tests.rs b/test_napi/tests/napi_tests.rs
index 3e3989436..c3ce285e0 100644
--- a/test_napi/tests/napi_tests.rs
+++ b/test_napi/tests/napi_tests.rs
@@ -18,6 +18,35 @@ fn build() {
}
let build_plugin_output = build_plugin.output().unwrap();
assert!(build_plugin_output.status.success());
+
+ // cc module.c -undefined dynamic_lookup -shared -Wl,-no_fixup_chains -dynamic -o module.dylib
+ #[cfg(not(target_os = "windows"))]
+ {
+ let out = if cfg!(target_os = "macos") {
+ "module.dylib"
+ } else {
+ "module.so"
+ };
+
+ let mut cc = Command::new("cc");
+
+ #[cfg(not(target_os = "macos"))]
+ let c_module = cc.arg("module.c").arg("-shared").arg("-o").arg(out);
+
+ #[cfg(target_os = "macos")]
+ let c_module = {
+ cc.arg("module.c")
+ .arg("-undefined")
+ .arg("dynamic_lookup")
+ .arg("-shared")
+ .arg("-Wl,-no_fixup_chains")
+ .arg("-dynamic")
+ .arg("-o")
+ .arg(out)
+ };
+ let c_module_output = c_module.output().unwrap();
+ assert!(c_module_output.status.success());
+ }
}
#[test]