diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2023-05-26 06:40:17 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-26 10:10:17 +0530 |
commit | 512d5337c480a2a2704881d3fe1c40b6e0445cf0 (patch) | |
tree | 99b03358883223a69f48b2d0e5b9387f3abae517 /test_napi | |
parent | 7ae55e75d812edc93251357465f8d49fc2fb5d26 (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/.gitignore | 5 | ||||
-rw-r--r-- | test_napi/common.js | 6 | ||||
-rw-r--r-- | test_napi/init_test.js | 14 | ||||
-rw-r--r-- | test_napi/module.c | 68 | ||||
-rw-r--r-- | test_napi/tests/napi_tests.rs | 29 |
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] |