Skip to content

Avoid double initialization when registering plugin EP libraries - #33701

Merged
Tianlei Wu (tianleiwu) merged 6 commits into
mainfrom
copilot/fix-provider-bridge-unload-issue
Nov 9, 2026
Merged

Tianlei Wu (tianleiwu) merged 6 commits into
mainfrom
copilot/fix-provider-bridge-unload-issue

Conversation

Copilot AI commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Description

  • Probe lifetime: Retain the DLL when GetProvider is absent until the plugin loader acquires its own reference. Preserve provider-bridge dependency initialization order.
  • Cleanup: Release the probe reference on success or failure; reuse retained handles on retries to prevent reference leaks. Preserve full unloading on unregistration.
  • Regression coverage: Add lifecycle fixtures covering single initialization, repeated registration, failed loads, and probe retries.

Motivation and Context

RegisterExecutionProviderLibrary unloads non-bridge plugin EPs after probing for GetProvider, then immediately reloads them. This repeats initialization and teardown of the EP DLL and its dependencies, adding an unnecessary DLL lifecycle to registration latency.

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI and others added 3 commits October 28, 2026 23:21
Co-authored-by: tianleiwu <30328909+tianleiwu@users.noreply.github.com>
Co-authored-by: tianleiwu <30328909+tianleiwu@users.noreply.github.com>
Co-authored-by: tianleiwu <30328909+tianleiwu@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix provider-bridge unloading issue for EP DLL Avoid double initialization when registering plugin EP libraries Oct 28, 2026

@tianleiwu Tianlei Wu (tianleiwu) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: COMMENT — the fix is correct and verified on Linux (the double load/unload reproduces on main and is gone with this PR). The findings below are non-blocking suggestions. The Windows CI legs should confirm the original report (#33603).

What I verified (Linux x86-64, AMD EPYC 7V12, GCC 13.2, Release; built together with #33700, whose files are disjoint)

  • PR head: optional_provider_probe_test 7/7 passed in both the regular and the no_exceptions variants (the 3 new tests ran, none skipped); onnxruntime_autoep_test 123/123 passed.
  • main production code + this PR's tests: PluginRegistrationInitializesOnceAndUnregisterUnloads fails (event history _LUL... where _L is expected, i.e. load / unload / load per registration) and FailedPluginLoadUnloadsRetainedProbe fails (_LULU vs _LU). The 4 pre-existing probe tests pass on both. RetainedPluginProbeCanRetryWithoutLeakingReferences calls the new Load(bool) overload, so it cannot be built against main.
# Severity Where Issue
1 Suggestion provider_bridge_library.h (inline) Load(true) can fail and leave the DLL loaded, moving the Unload() obligation to the caller while the destructor never unloads; document it or replace the bare bool with an enum / named probe API
2 Suggestion optional_provider_probe_test_library.cc (inline) The tests rely on dlclose / FreeLibrary running the fixture's static destructor synchronously; state the invariant next to the tracker (nit: the Windows event log stops recording at 63 characters)
3 Nitpick PR description No validation evidence, and the checklist items are unchecked

The control flow is correct on every path I traced: the gsl::finally guard in utils.cc drops the probe's reference on the plugin path (refcount 2 to 1 after EpLibraryPlugin::Load()), on plugin load failure (back to 0, so the retained library cannot leak) and on exceptions, and it is a no-op on the provider-bridge path where the library is moved into EpLibraryProviderBridge.

Not run: Windows (where #33603 was reported; the Linux fixture reproduces the same load/unload/load mechanism through dlopen reference counts), macOS, and the wider shared-lib test suite.

Document retained-load failure ownership and synchronous fixture unload requirements. Preserve Windows histories beyond 63 characters, diagnose environment-recording failures, and cover 128-character histories during repeated plugin registration/unload.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tianleiwu
Tianlei Wu (tianleiwu) marked this pull request as ready for review November 9, 2026 01:09
Copilot AI balanced review requested due to automatic review settings November 9, 2026 01:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues are reported for the plugin execution-provider registration lifecycle changes.

No open issues 🎉

What changed in this PR

Addresses #33603 by avoiding an unnecessary unload/reload cycle during plugin execution-provider registration, while preserving provider-bridge initialization order and unloading on unregistration.

Changes:

  • Retains the probe’s library reference until the plugin loader acquires its own.
  • Releases probe references on success or failure and reuses retained handles on retries.
  • Adds lifecycle fixtures and regression tests for initialization, repeated registration, failed loads, and retries.
File Description
onnxruntime/​test/​shared_lib/​optional_provider_probe_test.cc Adds registration, cleanup, and retry lifecycle tests.
onnxruntime/​test/​shared_lib/​optional_provider_probe_test_library.cc Adds plugin fixtures with load/unload tracking and failure scenarios.
onnxruntime/​core/​session/​utils.cc Retains the probe reference through plugin loading and ensures cleanup.
onnxruntime/​core/​session/​provider_bridge_ort.cc Supports retaining libraries without GetProvider and reusing retained handles.
onnxruntime/​core/​session/​provider_bridge_library.h Declares the retention option and documents caller cleanup responsibilities.
cmake/​onnxruntime_unittests.cmake Builds and stages the new plugin fixtures for probe tests.

Review effort: Balanced

Keep plugin fixtures independent of runtime/ONNX globals and give each fixture type a distinct load path. This prevents a provider image retained by Darwin or the ASan loader from satisfying a later plugin probe, while preserving synchronous registration/unload and retained-failure coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tianleiwu
Tianlei Wu (tianleiwu) merged commit 22fe617 into main Nov 9, 2026
127 of 137 checks passed
@tianleiwu
Tianlei Wu (tianleiwu) deleted the copilot/fix-provider-bridge-unload-issue branch November 9, 2026 22:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Plugin EP] Provider-bridge probe unloads the EP DLL, so RegisterExecutionProviderLibrary loads and initializes it twice

4 participants