diff --git a/src/dusk/mods/loader/context.cpp b/src/dusk/mods/loader/context.cpp index 9c8fe71db4..548f0bb06f 100644 --- a/src/dusk/mods/loader/context.cpp +++ b/src/dusk/mods/loader/context.cpp @@ -44,7 +44,9 @@ void fail_mod(LoadedMod& mod, ModResult code, std::string_view message) { const bool firstFailure = !mod.loadFailed; mod.active = false; mod.loadFailed = true; - mod.failureReason = message; + if (firstFailure || mod.failureReason.empty()) { + mod.failureReason = message; + } // Stop the failed mod's services from resolving; mods that required them fail in turn. // Pointers already handed to other mods stay callable since the library remains loaded. // Nothing else is torn down here: fail_mod can run mid-frame (e.g. from a failing mod diff --git a/src/dusk/mods/loader/loader.cpp b/src/dusk/mods/loader/loader.cpp index 3ce3ee65fa..e1bb2797c8 100644 --- a/src/dusk/mods/loader/loader.cpp +++ b/src/dusk/mods/loader/loader.cpp @@ -602,7 +602,7 @@ bool ModLoader::activate_mod(LoadedMod& mod) { if (result == MOD_OK && !mod.loadFailed) { mod.initialized = true; log::write(mod.metadata.id, LOG_LEVEL_TRACE, "mod_initialize succeeded"); - } else { + } else if (result != MOD_OK && !mod.loadFailed) { fail_mod(mod, result, lifecycle_error_message("mod_initialize", result, error)); } } catch (const std::exception& e) { diff --git a/src/dusk/mods/svc/resource.cpp b/src/dusk/mods/svc/resource.cpp index d96973f785..b03934560f 100644 --- a/src/dusk/mods/svc/resource.cpp +++ b/src/dusk/mods/svc/resource.cpp @@ -74,10 +74,18 @@ void resource_free(ModContext* context, ResourceBuffer* buffer) { { return; } - if (s_buffers.erase(buffer->data) == 0) { + auto* mod = mod_from_context(context); + const auto it = s_buffers.find(buffer->data); + if (it == s_buffers.end()) { Log.error("[{}] resource free: not a live loaded buffer", mod_id_from_context(context)); return; } + if (mod == nullptr || it->second != mod) { + Log.error("[{}] resource free: buffer is owned by '{}'", mod_id_from_context(context), + it->second != nullptr ? it->second->metadata.id : "unknown"); + return; + } + s_buffers.erase(it); std::free(buffer->data); buffer->data = nullptr; buffer->size = 0; diff --git a/src/dusk/mods/svc/texture.cpp b/src/dusk/mods/svc/texture.cpp index 7eada55739..63c8ba822b 100644 --- a/src/dusk/mods/svc/texture.cpp +++ b/src/dusk/mods/svc/texture.cpp @@ -281,6 +281,11 @@ uint64_t texture_register_raw( entry.gxFormat = data.gxFormat; entry.label = fmt::format("mod {} texture {}", mod.metadata.id, entry.handle); register_runtime_entry(entry, record.appliedPriority); + if (entry.registration.id == 0) { + Log.error("[{}] texture register_data failed: replacement was rejected", mod.metadata.id); + record.runtime.pop_back(); + return 0; + } return entry.handle; } @@ -377,6 +382,9 @@ ModResult texture_register_data(ModContext* context, const TextureKey* key, cons .mipCount = data->mip_count, .gxFormat = data->gx_format, }); + if (handle == 0) { + return MOD_INVALID_ARGUMENT; + } if (outHandle != nullptr) { *outHandle = handle; }