diff --git a/onnxruntime/core/session/plugin_ep/ep_library_plugin.cc b/onnxruntime/core/session/plugin_ep/ep_library_plugin.cc index ebfa364f4f1df..5197035e3e3e4 100644 --- a/onnxruntime/core/session/plugin_ep/ep_library_plugin.cc +++ b/onnxruntime/core/session/plugin_ep/ep_library_plugin.cc @@ -11,26 +11,36 @@ namespace onnxruntime { Status EpLibraryPlugin::Load() { auto status = Status::OK(); - std::lock_guard lock{mutex_}; ORT_TRY { + std::lock_guard lock{mutex_}; if (factories_.empty()) { - ORT_RETURN_IF_ERROR(Env::Default().LoadDynamicLibrary(library_path_, false, &handle_)); - ORT_RETURN_IF_ERROR(Env::Default().GetSymbolFromLibrary(handle_, "CreateEpFactories", - reinterpret_cast(&create_fn_))); - ORT_RETURN_IF_ERROR(Env::Default().GetSymbolFromLibrary(handle_, "ReleaseEpFactory", - reinterpret_cast(&release_fn_))); - - // allocate buffer for EP to add factories to. library can add up to 4 factories. - std::vector factories{4, nullptr}; - - size_t num_factories = 0; - ORT_RETURN_IF_ERROR(ToStatusAndRelease(create_fn_(registration_name_.c_str(), OrtGetApiBase(), - logging::LoggingManager::DefaultLogger().ToExternal(), - factories.data(), factories.size(), &num_factories))); - - for (size_t i = 0; i < num_factories; ++i) { - factories_.push_back(factories[i]); - } + // Run the load steps in an inner lambda so that an early error return from ORT_RETURN_IF_ERROR + // is captured in `status` rather than returning out of this function. That lets the cleanup + // below run on ANY failure path (error status or exception). Previously the ORT_RETURN_IF_ERROR + // returns bypassed the ORT_CATCH cleanup, so a partial load - e.g. the library handle was + // acquired but a required export was missing or CreateEpFactories failed - left the library + // loaded and half-initialized. + status = [&]() -> Status { + ORT_RETURN_IF_ERROR(Env::Default().LoadDynamicLibrary(library_path_, false, &handle_)); + ORT_RETURN_IF_ERROR(Env::Default().GetSymbolFromLibrary(handle_, "CreateEpFactories", + reinterpret_cast(&create_fn_))); + ORT_RETURN_IF_ERROR(Env::Default().GetSymbolFromLibrary(handle_, "ReleaseEpFactory", + reinterpret_cast(&release_fn_))); + + // allocate buffer for EP to add factories to. library can add up to 4 factories. + std::vector factories{4, nullptr}; + + size_t num_factories = 0; + ORT_RETURN_IF_ERROR(ToStatusAndRelease(create_fn_(registration_name_.c_str(), OrtGetApiBase(), + logging::LoggingManager::DefaultLogger().ToExternal(), + factories.data(), factories.size(), &num_factories))); + + for (size_t i = 0; i < num_factories; ++i) { + factories_.push_back(factories[i]); + } + + return Status::OK(); + }(); } } ORT_CATCH(const std::exception& ex) { @@ -38,14 +48,19 @@ Status EpLibraryPlugin::Load() { // TODO: Add logging of exception status = ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Failed to load execution provider library: ", library_path_, " with error: ", ex.what()); - auto unload_status = Unload(); // If anything fails we unload the library - if (!unload_status.IsOK()) { - LOGS_DEFAULT(ERROR) << "Failed to unload execution provider library: " << library_path_ << " with error: " - << unload_status.ErrorMessage(); - } }); } + // If the load failed for any reason (error status or exception), unload the library so a partial + // load does not leave it loaded and half-initialized. + if (!status.IsOK()) { + auto unload_status = Unload(); + if (!unload_status.IsOK()) { + LOGS_DEFAULT(ERROR) << "Failed to unload execution provider library: " << library_path_ << " with error: " + << unload_status.ErrorMessage(); + } + } + return status; }