Skip to content

Commit aa2f5fd

Browse files
author
ONNX GenAI Assistant
committed
Fix: Add explicit Shutdown() call to nanobind cleanup
The nanobind version was missing an explicit Generators::Shutdown() call during Python module cleanup that the pybind11 version had. This caused OrtGlobals to be destroyed too late (during C++ static destructors instead of during Python finalization), leading to use-after-free errors. The issue manifested as Invalid read errors in valgrind when ONNX Runtime CUDA provider memory was freed during session cleanup, but then accessed again when OrtEnv destructor ran. Changes: - Added #include "../generators.h" to access Generators::Shutdown() - Added Generators::Shutdown() call in the atexit cleanup lambda - Updated comments to clarify the cleanup sequence This ensures the same cleanup order as pybind11: 1. Python GC releases references 2. Generators::Shutdown() destroys OrtGlobals explicitly 3. Static destructor EnsureShutdown sees null and does nothing Valgrind results: - Before: 187 errors (including 2 Invalid reads) - After: 173 errors (no Invalid reads) - Matches pybind11 behavior (184 errors, no Invalid reads)
1 parent 0eda34b commit aa2f5fd

File tree

1 file changed

+5
-2
lines changed

1 file changed

+5
-2
lines changed

src/python/python.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "py_utils.h"
55
#include <nanobind/nanobind.h>
66
#include "../models/onnxruntime_api.h"
7+
#include "../generators.h"
78

89
namespace nb = nanobind;
910

@@ -77,10 +78,12 @@ NB_MODULE(onnxruntime_genai, m) {
7778
}, nb::arg("callback").none(), "Set a callback function for log messages. Pass None to clear.");
7879

7980
// Register cleanup function to run before Python shutdown
80-
// This ensures our objects are destroyed before LeakChecked counts are checked
81+
// This ensures OrtGlobals is destroyed before C++ static destructors run
8182
auto cleanup = []() {
82-
// Force Python GC to run before C++ static destructors
83+
// Force Python GC to run first to release Python-held references
8384
PyGC_Collect();
85+
// Explicitly call Shutdown to destroy OrtGlobals before static destructors
86+
Generators::Shutdown();
8487
};
8588

8689
// Use Python's atexit to register cleanup

0 commit comments

Comments
 (0)