From 0e16164ea6e6d6f86fe0b56e63f06899e2833718 Mon Sep 17 00:00:00 2001 From: Benoist <14257866+Kenzzer@users.noreply.github.com> Date: Wed, 27 May 2026 15:53:56 +0200 Subject: [PATCH 1/4] Fix use after free crash --- extension/extension.cpp | 27 ++++----------------------- extension/extension.h | 30 ++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/extension/extension.cpp b/extension/extension.cpp index d4a8f75..379a735 100644 --- a/extension/extension.cpp +++ b/extension/extension.cpp @@ -27,7 +27,6 @@ #include #include "MemoryDownloader.h" -#include "forwards.h" #include "natives.h" #if defined _LINUX @@ -1085,25 +1084,6 @@ class UploadThread: public IThread } } uploadThread; -class SourcePawnNotifyThread : public IThread -{ -public: - - void RunThread(IThreadHandle* pHandle) { - for (;;) { - // Wait until OnMapStart is called once, this should be enough delay to make sure plugins are loaded. - if (g_accelerator.IsMapStarted() && g_accelerator.IsDoneUploading()) { - extforwards::CallOnDoneUploadingForward(); - break; - } - } - } - - void OnTerminate(IThreadHandle* pHandle, bool cancel) { - } - -} spNotifyThread; - class VFuncEmptyClass {}; const char *GetCmdLine() @@ -1142,7 +1122,7 @@ const char *GetCmdLine() } Accelerator::Accelerator() : - m_doneuploading(false), m_maphasstarted(false) + m_doneuploading(false), m_maphasstarted(false), m_outter(this) { } @@ -1171,8 +1151,8 @@ bool Accelerator::SDK_OnLoad(char *error, size_t maxlength, bool late) strncpy(crashGameDirectory, g_pSM->GetGameFolderName(), sizeof(crashGameDirectory) - 1); threader->MakeThread(&uploadThread); - threader->MakeThread(&spNotifyThread); // This thread waits for accelator to be done uploading and for the first OnMapStart call, then fires a SourceMod forward - + threader->MakeThread(&m_spNotifyThread); // This thread waits for accelator to be done uploading and for the first OnMapStart call, then fires a SourceMod forward + do { char gameconfigError[256]; if (!gameconfs->LoadGameConfigFile("accelerator.games", &gameconfig, gameconfigError, sizeof(gameconfigError))) { @@ -1353,6 +1333,7 @@ void Accelerator::SDK_OnUnload() { extforwards::Shutdown(); plsys->RemovePluginsListener(this); + m_spNotifyThread.Shutdown(); #if defined _LINUX g_pSM->RemoveGameFrameHook(OnGameFrame); diff --git a/extension/extension.h b/extension/extension.h index 0412a7c..d1a721a 100644 --- a/extension/extension.h +++ b/extension/extension.h @@ -30,6 +30,7 @@ #include #include #include "smsdk_ext.h" +#include "forwards.h" /** * @brief Represents a crash that has been successfully uploaded to Accelerator's backend @@ -133,6 +134,35 @@ class Accelerator : public SDKExtension, IPluginsListener mutable std::mutex m_uploadedcrashes_mutex; // mutex for accessing the m_uploadedcrashes vector std::atomic_bool m_doneuploading; // Signals that Accelerator is done uploading crashes. std::atomic_bool m_maphasstarted; // Signals that OnMapStart has been called at least once. + + class SourcePawnNotifyThread : public IThread + { + public: + SourcePawnNotifyThread(Accelerator* outter) : m_outter(outter), m_terminated(false), m_shutdown(false) + ~SourcePawnNotifyThread() { while (!m_terminated) {} } + + void RunThread(IThreadHandle* pHandle) { + while (!m_shutdown) { + // Wait until OnMapStart is called once, this should be enough delay to make sure plugins are loaded. + if (m_outter.IsMapStarted() && m_outter.IsDoneUploading()) { + extforwards::CallOnDoneUploadingForward(); + break; + } + } + } + + void OnTerminate(IThreadHandle* pHandle, bool cancel) { + m_terminated = true; + } + + void Shutdown() { + m_shutdown = true; + } + + Accelerator* m_outter; + bool m_terminated; + bool m_shutdown; + } m_spNotifyThread; }; // Expose the extension singleton. From 2b68c81a9d0379209595a6d9a444035d8be1c74d Mon Sep 17 00:00:00 2001 From: Benoist <14257866+Kenzzer@users.noreply.github.com> Date: Wed, 27 May 2026 15:58:13 +0200 Subject: [PATCH 2/4] Add body to ctor --- extension/extension.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/extension.h b/extension/extension.h index d1a721a..a57dc66 100644 --- a/extension/extension.h +++ b/extension/extension.h @@ -138,7 +138,7 @@ class Accelerator : public SDKExtension, IPluginsListener class SourcePawnNotifyThread : public IThread { public: - SourcePawnNotifyThread(Accelerator* outter) : m_outter(outter), m_terminated(false), m_shutdown(false) + SourcePawnNotifyThread(Accelerator* outter) : m_outter(outter), m_terminated(false), m_shutdown(false) {} ~SourcePawnNotifyThread() { while (!m_terminated) {} } void RunThread(IThreadHandle* pHandle) { From 68f2fe4eff1170ff7dbda37868a3e36e57961cd6 Mon Sep 17 00:00:00 2001 From: Benoist <14257866+Kenzzer@users.noreply.github.com> Date: Wed, 27 May 2026 16:09:04 +0200 Subject: [PATCH 3/4] Compilation fix --- extension/extension.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/extension.h b/extension/extension.h index a57dc66..337ae46 100644 --- a/extension/extension.h +++ b/extension/extension.h @@ -144,7 +144,7 @@ class Accelerator : public SDKExtension, IPluginsListener void RunThread(IThreadHandle* pHandle) { while (!m_shutdown) { // Wait until OnMapStart is called once, this should be enough delay to make sure plugins are loaded. - if (m_outter.IsMapStarted() && m_outter.IsDoneUploading()) { + if (m_outter->IsMapStarted() && m_outter->IsDoneUploading()) { extforwards::CallOnDoneUploadingForward(); break; } From bdba6530ecb5969032be690224a0eff301c5ece4 Mon Sep 17 00:00:00 2001 From: Kenzzer <14257866+kenzzer@users.noreply.github.com> Date: Wed, 1 Jul 2026 22:06:51 +0000 Subject: [PATCH 4/4] Prepare the extension for SM 1.13 --- extension/extension.cpp | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/extension/extension.cpp b/extension/extension.cpp index 379a735..daa263b 100644 --- a/extension/extension.cpp +++ b/extension/extension.cpp @@ -1122,7 +1122,7 @@ const char *GetCmdLine() } Accelerator::Accelerator() : - m_doneuploading(false), m_maphasstarted(false), m_outter(this) + m_doneuploading(false), m_maphasstarted(false), m_spNotifyThread(this) { } @@ -1215,6 +1215,7 @@ bool Accelerator::SDK_OnLoad(char *error, size_t maxlength, bool late) #endif do { +#if SMINTERFACE_EXTENSIONAPI_VERSION < 9 char spJitPath[512]; g_pSM->BuildPath(Path_SM, spJitPath, sizeof(spJitPath), "bin/" PLATFORM_ARCH_FOLDER "sourcepawn.jit.x86." PLATFORM_LIB_EXT); @@ -1250,6 +1251,11 @@ bool Accelerator::SDK_OnLoad(char *error, size_t maxlength, bool late) } strncpy(crashSourceModVersion, spEngine2->GetVersionString(), sizeof(crashSourceModVersion)); +#else + auto engine = g_pSM->GetScriptingEngine(); + + strncpy(crashSourceModVersion, engine->GetVersionString(), sizeof(crashSourceModVersion)); +#endif } while(false); plsys->AddPluginsListener(this); @@ -1465,6 +1471,7 @@ void Accelerator::OnPluginLoaded(IPlugin *plugin) size += sizeof(void *); // GetBaseContext size += filenameSize; +#if SMINTERFACE_EXTENSIONAPI_VERSION < 9 uint32_t count = runtime->GetPublicsNum(); size += sizeof(uint32_t); // count size += count * sizeof(uint32_t); // pubinfo->code_offs @@ -1475,6 +1482,23 @@ void Accelerator::OnPluginLoaded(IPlugin *plugin) size += strlen(pubinfo->name) + 1; } +#else +static_assert(false, "Check the code below is still true."); +static_assert(sizeof(funcid_t) == 4, "funcid_t is no longer 4 bytes long."); + + // The count has to be discovered + uint32_t count = 0; + for (; count < ~(1 << 31); ++count) { + auto func_id = (count << 1) | 0x1; + auto func = runtime->GetFunctionById(func_id); + if (!func) { + break; + } + size += strlen(func->DebugName()) + 1; + } + size += sizeof(uint32_t); + size += count * sizeof(uint32_t); +#endif unsigned char *buffer = (unsigned char *)malloc(size); unsigned char *cursor = buffer; @@ -1492,6 +1516,7 @@ void Accelerator::OnPluginLoaded(IPlugin *plugin) cursor += sizeof(uint32_t); for (uint32_t i = 0; i < count; ++i) { +#if SMINTERFACE_EXTENSIONAPI_VERSION < 9 sp_public_t *pubinfo; runtime->GetPublicByIndex(i, &pubinfo); @@ -1501,6 +1526,18 @@ void Accelerator::OnPluginLoaded(IPlugin *plugin) size_t nameSize = strlen(pubinfo->name) + 1; memcpy(cursor, pubinfo->name, nameSize); cursor += nameSize; +#else + auto func_id = (i << 1) | 0x1; + auto func = runtime->GetFunctionById(func_id); + + // This information is no longer public + *(uint32_t*)cursor = 0x0; + cursor += sizeof(uint32_t); + + size_t nameSize = strlen(func->DebugName()) + 1; + memcpy(cursor, func->DebugName(), nameSize); + cursor += nameSize; +#endif } pluginContextMap[context] = buffer;