Skip to content

Commit 2134765

Browse files
committed
Fix crash at process exit on macOS
1 parent 860d085 commit 2134765

File tree

2 files changed

+29
-10
lines changed

2 files changed

+29
-10
lines changed

js/node/src/ort_instance_data.cc

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
#include "ort_instance_data.h"
99
#include "onnxruntime_cxx_api.h"
1010

11-
std::unique_ptr<Ort::Env> OrtInstanceData::ortEnv;
12-
std::unique_ptr<Ort::RunOptions> OrtInstanceData::ortDefaultRunOptions;
11+
Ort::Env* OrtInstanceData::ortEnv;
12+
Ort::RunOptions* OrtInstanceData::ortDefaultRunOptions;
1313
std::mutex OrtInstanceData::ortEnvMutex;
1414
std::atomic<uint64_t> OrtInstanceData::ortEnvRefCount;
1515
std::atomic<bool> OrtInstanceData::ortEnvDestroyed;
@@ -20,10 +20,29 @@ OrtInstanceData::OrtInstanceData() {
2020

2121
OrtInstanceData::~OrtInstanceData() {
2222
if (--ortEnvRefCount == 0) {
23+
// OrtInstanceData is the "instance data" for Napi::Env, so when the last Napi::Env using ORT is destroyed, we
24+
// clean up the global ORT env here.
25+
//
26+
// Note:
27+
// - The current function is not guaranteed to be called. In Node.js, the finalizer of the instance data may not be
28+
// called at certain scenarios, including but not limited to:
29+
// - Uncaught exceptions causing process termination.
30+
// - Process exit via process.exit().
31+
//
32+
// In those scenarios, the destructor won't be called, and the OS will reclaim all memory used by the process.
33+
// This helps avoid unexpected crashes during process shutdown due to the order of static destruction across
34+
// different translation units.
35+
//
36+
// For more details, see:
37+
// - https://github.com/microsoft/onnxruntime/issues/24579
38+
// - https://github.com/nodejs/node/issues/58341
39+
//
2340
std::lock_guard<std::mutex> lock(ortEnvMutex);
2441
if (ortEnv) {
25-
ortDefaultRunOptions.reset(nullptr);
26-
ortEnv.reset();
42+
delete ortDefaultRunOptions;
43+
ortDefaultRunOptions = nullptr;
44+
delete ortEnv;
45+
ortEnv = nullptr;
2746
ortEnvDestroyed = true;
2847
}
2948
}
@@ -46,8 +65,8 @@ void OrtInstanceData::InitOrt(Napi::Env env, int log_level, Napi::Function tenso
4665
std::lock_guard<std::mutex> lock(ortEnvMutex);
4766
if (!ortEnv) {
4867
ORT_NAPI_THROW_ERROR_IF(ortEnvDestroyed, env, "OrtEnv already destroyed.");
49-
ortEnv.reset(new Ort::Env{OrtLoggingLevel(log_level), "onnxruntime-node"});
50-
ortDefaultRunOptions.reset(new Ort::RunOptions{});
68+
ortEnv = new Ort::Env{OrtLoggingLevel(log_level), "onnxruntime-node"};
69+
ortDefaultRunOptions = new Ort::RunOptions{};
5170
}
5271
}
5372
}

js/node/src/ort_instance_data.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ struct OrtInstanceData {
2828
// Get the Tensor constructor reference for the Napi::Env
2929
static const Napi::FunctionReference& TensorConstructor(Napi::Env env);
3030
// Get the global Ort::Env
31-
static const Ort::Env* OrtEnv() { return ortEnv.get(); }
31+
static const Ort::Env* OrtEnv() { return ortEnv; }
3232
// Get the default Ort::RunOptions
33-
static Ort::RunOptions* OrtDefaultRunOptions() { return ortDefaultRunOptions.get(); }
33+
static const Ort::RunOptions* OrtDefaultRunOptions() { return ortDefaultRunOptions; }
3434

3535
~OrtInstanceData();
3636

@@ -42,8 +42,8 @@ struct OrtInstanceData {
4242
Napi::FunctionReference ortTensorConstructor;
4343

4444
// ORT env (global singleton)
45-
static std::unique_ptr<Ort::Env> ortEnv;
46-
static std::unique_ptr<Ort::RunOptions> ortDefaultRunOptions;
45+
static Ort::Env* ortEnv;
46+
static Ort::RunOptions* ortDefaultRunOptions;
4747
static std::mutex ortEnvMutex;
4848
static std::atomic<uint64_t> ortEnvRefCount;
4949
static std::atomic<bool> ortEnvDestroyed;

0 commit comments

Comments
 (0)