Fix session logger use-after-free during EP teardown under VERBOSE logging

Merged
CO
6mo ago
+124-3

Description

Move owned_session_logger_ declaration before execution_providers_ in InferenceSession so the logger outlives EPs during member destruction.

C++ destroys members in reverse declaration order. Previously:

~owned_session_logger_   (L905)  // logger freed
     ↓
~execution_providers_    (L745)  // EP teardown logs via dangling pointer → crash

After this change:

~execution_providers_    (L750)  // EP teardown logs safely ✅
     ↓
~owned_session_logger_   (L744)  // logger freed, no remaining users

Motivation and Context

Plugin EPs receive an OrtLogger* via OrtEpFactory::CreateEp(). During session destruction, EP teardown callbacks (e.g., ReleaseNodeComputeInfos) may log through this pointer. Because owned_session_logger_ was declared after execution_providers_, the logger was already freed when EPs destructed — a use-after-free that crashes deterministically under VERBOSE logging.

Affects all Plugin EPs that log in any teardown path. Reproduced with OpenVINO Plugin EP via webnn_graph_impl_fuzzer at VERBOSE level.

Fixes https://github.com/microsoft/onnxruntime/issues/28234

Tests Added

Added regression tests in onnxruntime/test/framework/inference_session_test.cc:

  • LoggingOnDestroyExecutionProvider — A mock EP that logs via its stored logger pointer in its destructor. If the logger has been freed, this triggers a use-after-free (detected by ASan or as a segfault).
  • SessionLoggerOutlivesEPsOnDestruction — Creates a session with VERBOSE logging and the mock EP, then destroys the session. Verifies that the logger was valid during EP teardown and that the teardown log message was captured.
  • SessionLoggerOutlivesEPsWithMultipleEPs — Same scenario with two mock EPs (distinct type names) to confirm all registered EPs can safely log during teardown.

Verification

Confirmed the tests are effective regression tests:

ScenarioResult
With fix (logger declared before EPs)Both tests pass ✅
Without fix (logger declared after EPs, original bug)SessionLoggerOutlivesEPsOnDestruction crashes with Segmentation fault (exit code 139) — use-after-free ❌

This proves the member declaration order is the critical factor, and the tests will catch any future regression that reorders these members.