From 75a98ba9aa932d76227d50e739ae4beb722a3cc6 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Mon, 16 Mar 2026 17:45:55 +0200 Subject: #5541 Add safety checks for inventory save during shutdown --- indra/newview/llinventorymodel.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'indra/newview/llinventorymodel.cpp') diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index c2f9c483c0..187b2248de 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -2383,10 +2383,22 @@ void LLInventoryModel::cache( items, INCLUDE_TRASH, can_cache); + + if (categories.empty() && items.empty()) + { + LL_WARNS(LOG_INV) << "Nothing to cache for " << parent_folder_id << LL_ENDL; + return; + } + // Use temporary file to avoid potential conflicts with other // instances (even a 'read only' instance unzips into a file) std::string temp_file = gDirUtilp->getTempFilename(); - saveToFile(temp_file, categories, items); + if (!saveToFile(temp_file, categories, items)) + { + LL_WARNS(LOG_INV) << "Failed to save inventory cache for " << parent_folder_id << LL_ENDL; + LLFile::remove(temp_file); + return; + } std::string gzip_filename = getInvCacheAddres(agent_id); gzip_filename.append(".gz"); if(gzip_file(temp_file, gzip_filename)) @@ -3537,6 +3549,11 @@ bool LLInventoryModel::saveToFile(const std::string& filename, S32 cat_count = 0; for (auto& cat : categories) { + if (cat.isNull()) + { + LL_WARNS(LOG_INV) << "Skipping null category during inventory save" << LL_ENDL; + continue; + } if (cat->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) { LLSD sd; @@ -3551,6 +3568,11 @@ bool LLInventoryModel::saveToFile(const std::string& filename, auto it_count = items.size(); for (auto& item : items) { + if (item.isNull()) + { + LL_WARNS(LOG_INV) << "Skipping null item during inventory save" << LL_ENDL; + continue; + } LLSD sd; item->asLLSD(sd); item_array.append(sd); -- cgit v1.3 From 5a7a5272a07935aae544767abc700e8fabf3cbbd Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Fri, 27 Mar 2026 19:46:38 +0200 Subject: #4298 Handle various out of memory cases --- indra/llrender/llfontfreetype.cpp | 43 +++++++++++++++++++++++--------------- indra/llrender/llshadermgr.cpp | 19 +++++++++++++++-- indra/newview/lldebugview.cpp | 4 ---- indra/newview/lldebugview.h | 1 - indra/newview/llinventorymodel.cpp | 6 ++++++ 5 files changed, 49 insertions(+), 24 deletions(-) (limited to 'indra/newview/llinventorymodel.cpp') diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp index d37b16ce0c..d9857a7ad5 100644 --- a/indra/llrender/llfontfreetype.cpp +++ b/indra/llrender/llfontfreetype.cpp @@ -871,30 +871,39 @@ namespace ll U8 const* LLFontManager::loadFont( std::string const &aFilename, long &a_Size) { - a_Size = 0; - std::map< std::string, std::shared_ptr >::iterator itr = m_LoadedFonts.find( aFilename ); - if( itr != m_LoadedFonts.end() ) + try { - ++itr->second->mRefs; - // A possible overflow cannot happen here, as it is asserted that the size is less than std::numeric_limits::max() a few lines below. - a_Size = static_cast(itr->second->mSize); - return reinterpret_cast(itr->second->mAddress.c_str()); - } + a_Size = 0; + std::map< std::string, std::shared_ptr >::iterator itr = m_LoadedFonts.find(aFilename); + if (itr != m_LoadedFonts.end()) + { + ++itr->second->mRefs; + // A possible overflow cannot happen here, as it is asserted that the size is less than std::numeric_limits::max() a few lines below. + a_Size = static_cast(itr->second->mSize); + return reinterpret_cast(itr->second->mAddress.c_str()); + } - auto strContent = LLFile::getContents(aFilename); + auto strContent = LLFile::getContents(aFilename); - if( strContent.empty() ) - return nullptr; + if (strContent.empty()) + return nullptr; - // For fontconfig a type of long is required, std::string::size() returns size_t. I think it is safe to limit this to 2GiB and not support fonts that huge (can that even be a thing?) - llassert_always( strContent.size() < std::numeric_limits::max() ); + // For fontconfig a type of long is required, std::string::size() returns size_t. I think it is safe to limit this to 2GiB and not support fonts that huge (can that even be a thing?) + llassert_always(strContent.size() < std::numeric_limits::max()); - a_Size = static_cast(strContent.size()); + a_Size = static_cast(strContent.size()); - auto pCache = std::make_shared( aFilename, strContent, a_Size ); - itr = m_LoadedFonts.insert( std::make_pair( aFilename, pCache ) ).first; + auto pCache = std::make_shared(aFilename, strContent, a_Size); + itr = m_LoadedFonts.insert(std::make_pair(aFilename, pCache)).first; - return reinterpret_cast(itr->second->mAddress.c_str()); + return reinterpret_cast(itr->second->mAddress.c_str()); + } + catch (const std::bad_alloc&) + { + LLError::LLUserWarningMsg::showOutOfMemory(); + LL_ERRS() << "Failed to load font. Out of memory." << LL_ENDL; + } + return nullptr; } void LLFontManager::unloadAllFonts() diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 2c35a6acae..b8545b3ed9 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1024,8 +1024,23 @@ void LLShaderMgr::initShaderCache(bool enabled, const LLUUID& old_cache_version, llifstream instream(meta_out_path, std::ifstream::in | std::ifstream::binary); LLSD in_data; - // todo: this is likely very expensive to parse, should use binary - LLSDSerialize::fromBinary(in_data, instream, LLSDSerialize::SIZE_UNLIMITED); + try + { + LLSDSerialize::fromBinary(in_data, instream, LLSDSerialize::SIZE_UNLIMITED); + } + catch( std::bad_alloc& ) + { + // Try to get a bit more memory back before we try to clear the cache. + in_data.clear(); + // Just in case it was somehow the cause, clear cache. + clearShaderCache(); + // If user run out of memory this early in init, + // we don't want to keep going just to crash again. + // Notify user and close. + LLError::LLUserWarningMsg::showOutOfMemory(); + LL_ERRS("ShaderMgr") << "Failed to parse shader cache metadata, potentially due to size. Purged cache." << LL_ENDL; + return; + } instream.close(); if (old_cache_version == current_cache_version diff --git a/indra/newview/lldebugview.cpp b/indra/newview/lldebugview.cpp index 53da9826ed..3941b82e75 100644 --- a/indra/newview/lldebugview.cpp +++ b/indra/newview/lldebugview.cpp @@ -38,7 +38,6 @@ #include "llappviewer.h" #include "llsceneview.h" #include "llviewertexture.h" -#include "llfloaterreg.h" #include "llscenemonitor.h" // // Globals @@ -53,7 +52,6 @@ static LLDefaultChildRegistry::Register r("debug_view"); LLDebugView::LLDebugView(const LLDebugView::Params& p) : LLView(p), - mFastTimerView(NULL), mDebugConsolep(NULL), mFloaterSnapRegion(NULL) {} @@ -89,8 +87,6 @@ void LLDebugView::init() r.setLeftTopAndSize(25, rect.getHeight() - 50, (S32) (gViewerWindow->getWindowRectScaled().getWidth() * 0.75f), (S32) (gViewerWindow->getWindowRectScaled().getHeight() * 0.75f)); - mFastTimerView = dynamic_cast(LLFloaterReg::getInstance("block_timers")); - gSceneView = new LLSceneView(r); gSceneView->setFollowsTop(); gSceneView->setFollowsLeft(); diff --git a/indra/newview/lldebugview.h b/indra/newview/lldebugview.h index 8fa2acc3c9..ca274d6f91 100644 --- a/indra/newview/lldebugview.h +++ b/indra/newview/lldebugview.h @@ -59,7 +59,6 @@ public: void setStatsVisible(bool visible); - LLFastTimerView* mFastTimerView; LLConsole* mDebugConsolep; LLView* mFloaterSnapRegion; }; diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 187b2248de..8b9aad4641 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -3589,6 +3589,12 @@ bool LLInventoryModel::saveToFile(const std::string& filename, LL_INFOS(LOG_INV) << "Inventory saved: " << (S32)cat_count << " categories, " << (S32)it_count << " items." << LL_ENDL; } + catch(std::bad_alloc&) + { + // We are quiting, so just log an error and move on. + LL_WARNS(LOG_INV) << "Failed to save inventory to cache due to memory allocation failure." << LL_ENDL; + return false; + } catch (...) { LOG_UNHANDLED_EXCEPTION(""); -- cgit v1.3