Describe the issue
OrtApi::RegisterExecutionProviderLibrary leaks one Win32 / dlopen reference on the EP DLL when the registered DLL does not export GetProvider (i.e. plugin EPs, e.g. onnxruntime_vitisai_ep.dll).
After a single Register + Unregister + ReleaseEnv cycle the EP DLL is still mapped (refcount = 1). On Windows this often surfaces as a STATUS_STACK_BUFFER_OVERRUN (0xC0000409) fast-fail during process teardown because the EP DLL outlives Unregister.
Root cause: ProviderLibrary::Load() (in onnxruntime/core/session/provider_bridge_ort.cc) calls LoadDynamicLibrary and then GetSymbolFromLibrary("GetProvider", ...). When the symbol lookup fails, ORT_RETURN_IF_ERROR returns early without calling Unload(). ~ProviderLibrary() is empty, so the temporary provider_library constructed by LoadPluginOrProviderBridge (in utils.cc) silently leaks its handle. EpLibraryPlugin::Load() then LoadDynamicLibrarys the same DLL again — refcount = 2 — and UnregisterExecutionProviderLibrary only releases one reference.
To reproduce
Standalone Win32 reproducer (no model, no inference, no link against onnxruntime.lib):
https://github.com/BoarQing/ep_double_load_repro
loaded onnxruntime.dll (runtime ORT version: 1.25.0)
ep dll leaked refcount after Unregister+ReleaseEnv = 1 <-- expected 0
Fix
PR #28396 — call Unload() in ProviderLibrary::Load() when the GetProvider symbol lookup fails. With the patch, the repro reports = 0.
Platform
Windows
OS Version
Windows 10.0.26100 (24H2), x64
ONNX Runtime Installation
Built from Source
ONNX Runtime Version or Commit ID
1.25.0 (also reproduces on main at e3c34da)
ONNX Runtime API
C
Architecture
X64
Execution Provider
Vitis AI
Execution Provider Library Version
onnxruntime_vitisai_ep.dll (registered via RegisterExecutionProviderLibrary("VitisAIExecutionProvider", ...)). The bug is in generic loader code, so it should reproduce with any plugin EP DLL that does not export GetProvider.
Describe the issue
OrtApi::RegisterExecutionProviderLibraryleaks one Win32 / dlopen reference on the EP DLL when the registered DLL does not exportGetProvider(i.e. plugin EPs, e.g.onnxruntime_vitisai_ep.dll).After a single
Register+Unregister+ReleaseEnvcycle the EP DLL is still mapped (refcount = 1). On Windows this often surfaces as aSTATUS_STACK_BUFFER_OVERRUN(0xC0000409) fast-fail during process teardown because the EP DLL outlivesUnregister.Root cause:
ProviderLibrary::Load()(inonnxruntime/core/session/provider_bridge_ort.cc) callsLoadDynamicLibraryand thenGetSymbolFromLibrary("GetProvider", ...). When the symbol lookup fails,ORT_RETURN_IF_ERRORreturns early without callingUnload().~ProviderLibrary()is empty, so the temporaryprovider_libraryconstructed byLoadPluginOrProviderBridge(inutils.cc) silently leaks its handle.EpLibraryPlugin::Load()thenLoadDynamicLibrarys the same DLL again — refcount = 2 — andUnregisterExecutionProviderLibraryonly releases one reference.To reproduce
Standalone Win32 reproducer (no model, no inference, no link against
onnxruntime.lib):https://github.com/BoarQing/ep_double_load_repro
Fix
PR #28396 — call
Unload()inProviderLibrary::Load()when theGetProvidersymbol lookup fails. With the patch, the repro reports= 0.Platform
Windows
OS Version
Windows 10.0.26100 (24H2), x64
ONNX Runtime Installation
Built from Source
ONNX Runtime Version or Commit ID
1.25.0 (also reproduces on
mainat e3c34da)ONNX Runtime API
C
Architecture
X64
Execution Provider
Vitis AI
Execution Provider Library Version
onnxruntime_vitisai_ep.dll(registered viaRegisterExecutionProviderLibrary("VitisAIExecutionProvider", ...)). The bug is in generic loader code, so it should reproduce with any plugin EP DLL that does not exportGetProvider.