From e706c2fe674697e3b7028f6fdd6b0e3c69763470 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Fri, 19 Jun 2026 23:31:26 +0300 Subject: [PATCH 1/2] #4298 Handle OOM in loadCachedProgramBinary sanity check size, catch exceptions. Cache isn't mission critical. --- indra/llrender/llshadermgr.cpp | 57 +++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index b8545b3ed9c..c77a7ff8f18 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1142,34 +1142,55 @@ bool LLShaderMgr::loadCachedProgramBinary(LLGLSLShader* shader) { std::string in_path = gDirUtilp->add(mShaderCacheDir, shader->mShaderHash.asString() + ".shaderbin"); auto& shader_info = binary_iter->second; - if (shader_info.mBinaryLength > 0) - { - std::vector in_data; - in_data.resize(shader_info.mBinaryLength); - LLUniqueFile filep = LLFile::fopen(in_path, "rb"); - if (filep) + try + { + constexpr GLsizei MAX_SHADER_BINARY_SIZE = 1024 * 1024; // 1 MB, normally around 10KB + if (shader_info.mBinaryLength > 0 && shader_info.mBinaryLength <= MAX_SHADER_BINARY_SIZE) { - size_t result = fread(in_data.data(), sizeof(U8), in_data.size(), filep); - filep.close(); + std::vector in_data; + in_data.resize(shader_info.mBinaryLength); - if (result == in_data.size()) + LLUniqueFile filep = LLFile::fopen(in_path, "rb"); + if (filep) { - GLenum error = glGetError(); // Clear current error - glProgramBinary(shader->mProgramObject, shader_info.mBinaryFormat, in_data.data(), shader_info.mBinaryLength); + size_t result = fread(in_data.data(), sizeof(U8), in_data.size(), filep); + filep.close(); - error = glGetError(); - GLint success = GL_TRUE; - glGetProgramiv(shader->mProgramObject, GL_LINK_STATUS, &success); - if (error == GL_NO_ERROR && success == GL_TRUE) + if (result == in_data.size()) { - binary_iter->second.mLastUsedTime = (F32)LLTimer::getTotalSeconds(); - LL_INFOS() << "Loaded cached binary for shader: " << shader->mName << LL_ENDL; - return true; + GLenum error = glGetError(); // Clear current error + glProgramBinary(shader->mProgramObject, shader_info.mBinaryFormat, in_data.data(), shader_info.mBinaryLength); + + error = glGetError(); + GLint success = GL_TRUE; + glGetProgramiv(shader->mProgramObject, GL_LINK_STATUS, &success); + if (error == GL_NO_ERROR && success == GL_TRUE) + { + binary_iter->second.mLastUsedTime = (F32)LLTimer::getTotalSeconds(); + LL_INFOS() << "Loaded cached binary for shader: " << shader->mName << LL_ENDL; + return true; + } + } + else + { + LL_WARNS("ShaderMgr") << "Incomplete read of shader binary. Expected: " + << in_data.size() << ", read: " << result << LL_ENDL; } } } } + catch (const std::bad_alloc&) + { + LL_WARNS("ShaderMgr") << "Failed to allocate memory for shader binary (" + << shader_info.mBinaryLength << " bytes) for: " + << shader->mName << LL_ENDL; + } + catch (const std::exception& err) + { + LL_WARNS("ShaderMgr") << "Caught exception " << err.what() << " while loading shader binary for: " << shader->mName << LL_ENDL; + } + //an error occured, normally we would print log but in this case it means the shader needs recompiling. LL_INFOS() << "Failed to load cached binary for shader: " << shader->mName << " falling back to compilation" << LL_ENDL; LLFile::remove(in_path); From eb8328726e6c0ca42687ce9d4751d24a554ad38a Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Fri, 19 Jun 2026 23:32:32 +0300 Subject: [PATCH 2/2] #5084 Include watchdog's state in crash report to help diagnose crashes --- indra/llcommon/llwatchdog.cpp | 5 +++++ indra/llcommon/llwatchdog.h | 2 ++ indra/newview/llappviewer.cpp | 26 ++++++++++++++++++++++++++ indra/newview/llappviewer.h | 1 + indra/newview/llappviewerwin32.cpp | 8 ++++++++ 5 files changed, 42 insertions(+) diff --git a/indra/llcommon/llwatchdog.cpp b/indra/llcommon/llwatchdog.cpp index 66b565c7634..fd0702733c0 100644 --- a/indra/llcommon/llwatchdog.cpp +++ b/indra/llcommon/llwatchdog.cpp @@ -116,6 +116,11 @@ bool LLWatchdogTimeout::isAlive() const return (mTimer.getStarted() && !mTimer.hasExpired()); } +bool LLWatchdogTimeout::hasExpired() const +{ + return mTimer.hasExpired(); +} + void LLWatchdogTimeout::reset() { mTimer.setTimerExpirySec(mTimeout); diff --git a/indra/llcommon/llwatchdog.h b/indra/llcommon/llwatchdog.h index f138fbccb05..b286dd179d5 100644 --- a/indra/llcommon/llwatchdog.h +++ b/indra/llcommon/llwatchdog.h @@ -47,6 +47,7 @@ class LLWatchdogEntry // This may mean that resources used by // isAlive and other method may need synchronization. virtual bool isAlive() const = 0; + virtual bool hasExpired() const = 0; virtual void reset() = 0; virtual void start(); virtual void stop(); @@ -66,6 +67,7 @@ class LLWatchdogTimeout : public LLWatchdogEntry virtual ~LLWatchdogTimeout(); bool isAlive() const override; + bool hasExpired() const override; void reset() override; void start() override { start(""); } void stop() override; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 263c1f20540..58e3aea9b79 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -6321,6 +6321,32 @@ F32 LLAppViewer::getMainloopTimeoutSec() const } } +std::string LLAppViewer::getMainloopWatchdogState() const +{ + if (!mMainloopTimeout) + { + return std::string(); + } + std::string state = mMainloopTimeout->getState(); + + if (mMainloopTimeout->hasExpired()) + { + return "Expired at " + state; + } + + // Check if the watchdog is currently active (timer started) + if (!mMainloopTimeout->isAlive()) + { + // Timer is not running, meaning watchdog is paused/stopped + if (state.empty()) + { + return "Paused"; + } + return "Paused at " + state; + } + return state; +} + void LLAppViewer::handleLoginComplete() { gLoggedInTime.start(); diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 6ecafae0363..1b1a89d7566 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -212,6 +212,7 @@ class LLAppViewer : public LLApp void pingMainloopTimeout(std::string_view state); F32 getMainloopTimeoutSec() const; + std::string getMainloopWatchdogState() const; // Handle the 'login completed' event. // *NOTE:Mani Fix this for login abstraction!! diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 25aeb2a26e2..416efa93545 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -193,6 +193,14 @@ namespace } LLAppViewer* app = LLAppViewer::instance(); + + // Include mainloop watchdog state if available + std::string watchdog_state = app->getMainloopWatchdogState(); + if (!watchdog_state.empty()) + { + sBugSplatSender->setAttribute(WCSTR(L"WatchdogState"), WCSTR(watchdog_state)); + } + if (!app->isSecondInstance() && !app->errorMarkerExists()) { // If marker doesn't exist, create a marker with 'other' or 'logout' code for next launch