From 37e5a0b6629545ab58fe437d81514e5ce928715e Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 29 Sep 2021 22:47:58 +0300 Subject: SL-13934 Crash at saveToFile --- indra/newview/llinventorymodel.cpp | 67 +++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 29 deletions(-) (limited to 'indra/newview/llinventorymodel.cpp') diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 28db6a5808..5abc335d39 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -2803,42 +2803,51 @@ bool LLInventoryModel::saveToFile(const std::string& filename, LL_INFOS(LOG_INV) << "saving inventory to: (" << filename << ")" << LL_ENDL; - llofstream fileXML(filename.c_str()); - if (!fileXML.is_open()) - { - LL_WARNS(LOG_INV) << "unable to save inventory to: " << filename << LL_ENDL; - return false; - } + try + { + llofstream fileXML(filename.c_str()); + if (!fileXML.is_open()) + { + LL_WARNS(LOG_INV) << "unable to save inventory to: " << filename << LL_ENDL; + return false; + } - LLSD cache_ver; - cache_ver["inv_cache_version"] = sCurrentInvCacheVersion; + LLSD cache_ver; + cache_ver["inv_cache_version"] = sCurrentInvCacheVersion; - fileXML << LLSDOStreamer(cache_ver) << std::endl; + fileXML << LLSDOStreamer(cache_ver) << std::endl; - S32 count = categories.size(); - S32 cat_count = 0; - S32 i; - for(i = 0; i < count; ++i) - { - LLViewerInventoryCategory* cat = categories[i]; - if(cat->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) - { - fileXML << LLSDOStreamer(cat->exportLLSD()) << std::endl; - cat_count++; - } - } + S32 count = categories.size(); + S32 cat_count = 0; + S32 i; + for (i = 0; i < count; ++i) + { + LLViewerInventoryCategory* cat = categories[i]; + if (cat->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) + { + fileXML << LLSDOStreamer(cat->exportLLSD()) << std::endl; + cat_count++; + } + } - S32 it_count = items.size(); - for(i = 0; i < it_count; ++i) - { - fileXML << LLSDOStreamer(items[i]->asLLSD()) << std::endl; - } + S32 it_count = items.size(); + for (i = 0; i < it_count; ++i) + { + fileXML << LLSDOStreamer(items[i]->asLLSD()) << std::endl; + } - fileXML.close(); + fileXML.close(); - LL_INFOS(LOG_INV) << "Inventory saved: " << cat_count << " categories, " << it_count << " items." << LL_ENDL; + LL_INFOS(LOG_INV) << "Inventory saved: " << cat_count << " categories, " << it_count << " items." << LL_ENDL; + } + catch (...) + { + LOG_UNHANDLED_EXCEPTION(""); + LL_INFOS(LOG_INV) << "Failed to save inventory to: (" << filename << ")" << LL_ENDL; + return false; + } - return true; + return true; } // message handling functionality -- cgit v1.2.3 From 1dffd2a2fe8b2c0835460b84fd63fd19aa74d890 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 1 Oct 2021 18:21:05 +0300 Subject: SL-13934 Crash at saveToFile #2 More detailed stream handling and logging --- indra/newview/llinventorymodel.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'indra/newview/llinventorymodel.cpp') diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 5abc335d39..72281d9e4c 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -2808,13 +2808,19 @@ bool LLInventoryModel::saveToFile(const std::string& filename, llofstream fileXML(filename.c_str()); if (!fileXML.is_open()) { - LL_WARNS(LOG_INV) << "unable to save inventory to: " << filename << LL_ENDL; + LL_WARNS(LOG_INV) << "Failed to open file. Unable to save inventory to: " << filename << LL_ENDL; return false; } LLSD cache_ver; cache_ver["inv_cache_version"] = sCurrentInvCacheVersion; + if (fileXML.fail()) + { + LL_WARNS(LOG_INV) << "Failed to write cache version to file. Unable to save inventory to: " << filename << LL_ENDL; + return false; + } + fileXML << LLSDOStreamer(cache_ver) << std::endl; S32 count = categories.size(); @@ -2828,12 +2834,24 @@ bool LLInventoryModel::saveToFile(const std::string& filename, fileXML << LLSDOStreamer(cat->exportLLSD()) << std::endl; cat_count++; } + + if (fileXML.fail()) + { + LL_WARNS(LOG_INV) << "Failed to write a folder to file. Unable to save inventory to: " << filename << LL_ENDL; + return false; + } } S32 it_count = items.size(); for (i = 0; i < it_count; ++i) { fileXML << LLSDOStreamer(items[i]->asLLSD()) << std::endl; + + if (fileXML.fail()) + { + LL_WARNS(LOG_INV) << "Failed to write an item to file. Unable to save inventory to: " << filename << LL_ENDL; + return false; + } } fileXML.close(); -- cgit v1.2.3 From 4a4c1388919167f14ef9b48bd2709b07af8b0685 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 7 Mar 2022 22:25:22 +0200 Subject: SL-16984 Fixed inventory loop freezing viewer --- indra/newview/llinventorymodel.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'indra/newview/llinventorymodel.cpp') diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 29fbcc968f..ea22750c1f 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -340,12 +340,26 @@ const LLViewerInventoryCategory* LLInventoryModel::getFirstDescendantOf(const LL bool LLInventoryModel::getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const { LLInventoryObject *object = getObject(object_id); - while (object && object->getParentUUID().notNull()) - { - LLInventoryObject *parent_object = getObject(object->getParentUUID()); + if (!object) + { + LL_WARNS(LOG_INV) << "Unable to trace topmost ancestor, initial object " << object_id << " does not exist" << LL_ENDL; + return false; + } + + std::set object_ids{ object_id }; // loop protection + while (object->getParentUUID().notNull()) + { + LLUUID parent_id = object->getParentUUID(); + if (object_ids.find(parent_id) != object_ids.end()) + { + LL_WARNS(LOG_INV) << "Detected a loop on an object " << parent_id << " when searching for ancestor of " << object_id << LL_ENDL; + return false; + } + object_ids.insert(parent_id); + LLInventoryObject *parent_object = getObject(parent_id); if (!parent_object) { - LL_WARNS(LOG_INV) << "unable to trace topmost ancestor, missing item for uuid " << object->getParentUUID() << LL_ENDL; + LL_WARNS(LOG_INV) << "unable to trace topmost ancestor of " << object_id << ", missing item for uuid " << parent_id << LL_ENDL; return false; } object = parent_object; -- cgit v1.2.3 From b7c58427bf228aaaef5938bc99a8d9f679bd15ce Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 10 Mar 2022 00:04:19 +0200 Subject: SL-16984 Loop tracking and logging --- indra/newview/llinventorymodel.cpp | 89 +++++++++++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 21 deletions(-) (limited to 'indra/newview/llinventorymodel.cpp') diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index ea22750c1f..8ddba510b4 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -138,6 +138,8 @@ bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item) LLInventoryValidationInfo::LLInventoryValidationInfo(): mFatalErrorCount(0), mWarningCount(0), + mLoopCount(0), + mOrphanedCount(0), mInitialized(false), mFatalNoRootFolder(false), mFatalNoLibraryRootFolder(false), @@ -147,7 +149,10 @@ LLInventoryValidationInfo::LLInventoryValidationInfo(): void LLInventoryValidationInfo::toOstream(std::ostream& os) const { - os << "mFatalErrorCount " << mFatalErrorCount << " mWarningCount " << mWarningCount; + os << "mFatalErrorCount " << mFatalErrorCount + << " mWarningCount " << mWarningCount + << " mLoopCount " << mLoopCount + << " mOrphanedCount " << mOrphanedCount; } @@ -161,6 +166,8 @@ void LLInventoryValidationInfo::asLLSD(LLSD& sd) const { sd["fatal_error_count"] = mFatalErrorCount; sd["warning_count"] = mWarningCount; + sd["loop_count"] = mLoopCount; + sd["orphaned_count"] = mOrphanedCount; sd["initialized"] = mInitialized; sd["missing_system_folders_count"] = LLSD::Integer(mMissingRequiredSystemFolders.size()); sd["fatal_no_root_folder"] = mFatalNoRootFolder; @@ -337,13 +344,13 @@ const LLViewerInventoryCategory* LLInventoryModel::getFirstDescendantOf(const LL return NULL; } -bool LLInventoryModel::getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const +LLInventoryModel::EAnscestorResult LLInventoryModel::getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const { LLInventoryObject *object = getObject(object_id); if (!object) { LL_WARNS(LOG_INV) << "Unable to trace topmost ancestor, initial object " << object_id << " does not exist" << LL_ENDL; - return false; + return ANSCESTOR_MISSING; } std::set object_ids{ object_id }; // loop protection @@ -353,19 +360,19 @@ bool LLInventoryModel::getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& if (object_ids.find(parent_id) != object_ids.end()) { LL_WARNS(LOG_INV) << "Detected a loop on an object " << parent_id << " when searching for ancestor of " << object_id << LL_ENDL; - return false; + return ANSCESTOR_LOOP; } object_ids.insert(parent_id); LLInventoryObject *parent_object = getObject(parent_id); if (!parent_object) { LL_WARNS(LOG_INV) << "unable to trace topmost ancestor of " << object_id << ", missing item for uuid " << parent_id << LL_ENDL; - return false; + return ANSCESTOR_MISSING; } object = parent_object; } result = object->getUUID(); - return true; + return ANSCESTOR_OK; } // Get the object by id. Returns NULL if not found. @@ -3891,20 +3898,23 @@ void LLInventoryModel::dumpInventory() const LLPointer LLInventoryModel::validate() const { LLPointer validation_info = new LLInventoryValidationInfo; - S32 fatalities = 0; + S32 fatal_errs = 0; S32 warnings = 0; + S32 loops = 0; + S32 orphaned = 0; if (getRootFolderID().isNull()) { LL_WARNS("Inventory") << "Fatal inventory corruption: no root folder id" << LL_ENDL; validation_info->mFatalNoRootFolder = true; - fatalities++; + fatal_errs++; } if (getLibraryRootFolderID().isNull()) { + // Probably shouldn't be a fatality, inventory can function without a library LL_WARNS("Inventory") << "Fatal inventory corruption: no library root folder id" << LL_ENDL; validation_info->mFatalNoLibraryRootFolder = true; - fatalities++; + fatal_errs++; } if (mCategoryMap.size() + 1 != mParentChildCategoryTree.size()) @@ -3936,7 +3946,23 @@ LLPointer LLInventoryModel::validate() const } LLUUID topmost_ancestor_id; // Will leave as null uuid on failure - getObjectTopmostAncestor(cat_id, topmost_ancestor_id); + EAnscestorResult res = getObjectTopmostAncestor(cat_id, topmost_ancestor_id); + switch (res) + { + case ANSCESTOR_MISSING: + orphaned++; + break; + case ANSCESTOR_LOOP: + loops++; + break; + case ANSCESTOR_OK: + break; + default: + LL_WARNS("Inventory") << "Unknown ancestor error for " << cat_id << LL_ENDL; + warnings++; + break; + } + if (cat_id != cat->getUUID()) { LL_WARNS("Inventory") << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL; @@ -4036,8 +4062,8 @@ LLPointer LLInventoryModel::validate() const // Topmost ancestor should be root or library. LLUUID topmost_ancestor_id; - bool found = getObjectTopmostAncestor(item_id, topmost_ancestor_id); - if (!found) + EAnscestorResult found = getObjectTopmostAncestor(item_id, topmost_ancestor_id); + if (found != ANSCESTOR_OK) { LL_WARNS("Inventory") << "unable to find topmost ancestor for " << item_id << LL_ENDL; warnings++; @@ -4067,7 +4093,7 @@ LLPointer LLInventoryModel::validate() const { LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName() << "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL; - warnings++; + orphaned++; } else { @@ -4085,6 +4111,7 @@ LLPointer LLInventoryModel::validate() const { LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName() << "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL; + orphaned++; } } } @@ -4093,7 +4120,7 @@ LLPointer LLInventoryModel::validate() const LLFolderType::EType folder_type = cat->getPreferredType(); bool cat_is_in_library = false; LLUUID topmost_id; - if (getObjectTopmostAncestor(cat->getUUID(),topmost_id) && topmost_id == getLibraryRootFolderID()) + if (getObjectTopmostAncestor(cat->getUUID(),topmost_id) == ANSCESTOR_OK && topmost_id == getLibraryRootFolderID()) { cat_is_in_library = true; } @@ -4133,6 +4160,7 @@ LLPointer LLInventoryModel::validate() const if (parent_id.isNull()) { LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL; + orphaned++; } else { @@ -4143,6 +4171,7 @@ LLPointer LLInventoryModel::validate() const { LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() << "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL; + orphaned++; } else { @@ -4159,6 +4188,7 @@ LLPointer LLInventoryModel::validate() const { LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() << "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL; + orphaned++; } } @@ -4176,15 +4206,18 @@ LLPointer LLInventoryModel::validate() const LL_WARNS("Inventory") << "link " << item->getUUID() << " type " << item->getActualType() << " missing backlink info at target_id " << target_id << LL_ENDL; + orphaned++; } // Links should have referents. if (item->getActualType() == LLAssetType::AT_LINK && !target_item) { LL_WARNS("Inventory") << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL; + orphaned++; } else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER && !target_cat) { LL_WARNS("Inventory") << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL; + orphaned++; } if (target_item && target_item->getIsLinkType()) { @@ -4256,8 +4289,8 @@ LLPointer LLInventoryModel::validate() const if (is_automatic) { LL_WARNS("Inventory") << "Fatal inventory corruption: cannot create system folder of type " << ft << LL_ENDL; - fatalities++; - validation_info->mMissingRequiredSystemFolders.insert(LLFolderType::EType(ft)); + fatal_errs++; + validation_info->mMissingRequiredSystemFolders.insert(folder_type); } else { @@ -4268,8 +4301,20 @@ LLPointer LLInventoryModel::validate() const else if (count_under_root > 1) { LL_WARNS("Inventory") << "Fatal inventory corruption: system folder type has excess copies under root, type " << ft << " count " << count_under_root << LL_ENDL; - validation_info->mDuplicateRequiredSystemFolders.insert(LLFolderType::EType(ft)); - fatalities++; + validation_info->mDuplicateRequiredSystemFolders.insert(folder_type); + if (!is_automatic) + { + // It is a fatal problem or can lead to fatal problems for COF, + // outfits and trash and other non-automatic folders. + // Exception: FT_SETTINGS likely only deserves a warning. + fatal_errs++; + } + else + { + // For automatic folders it's not a fatal issue and shouldn't + // break inventory or other functionality further + warnings++; + } } if (count_elsewhere > 0) { @@ -4295,11 +4340,13 @@ LLPointer LLInventoryModel::validate() const } // FIXME need to fail login and tell user to retry, contact support if problem persists. - bool valid = (fatalities == 0); - LL_INFOS("Inventory") << "Validate done, fatal errors: " << fatalities << ", warnings: " << warnings << ", valid: " << valid << LL_ENDL; + bool valid = (fatal_errs == 0); + LL_INFOS("Inventory") << "Validate done, fatal errors: " << fatal_errs << ", warnings: " << warnings << ", valid: " << valid << LL_ENDL; - validation_info->mFatalErrorCount = fatalities; + validation_info->mFatalErrorCount = fatal_errs; validation_info->mWarningCount = warnings; + validation_info->mLoopCount = loops; + validation_info->mOrphanedCount = orphaned; return validation_info; } -- cgit v1.2.3 From 6ab212c96b30c272acdc1d772d2c597fb58c8910 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 18 Mar 2022 14:14:38 +0200 Subject: SL-16984 Dupplicated FT_SETTINGS shouldn't prevent inventory from loading --- indra/newview/llinventorymodel.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/newview/llinventorymodel.cpp') diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 8ddba510b4..37500176ea 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -4302,17 +4302,17 @@ LLPointer LLInventoryModel::validate() const { LL_WARNS("Inventory") << "Fatal inventory corruption: system folder type has excess copies under root, type " << ft << " count " << count_under_root << LL_ENDL; validation_info->mDuplicateRequiredSystemFolders.insert(folder_type); - if (!is_automatic) + if (!is_automatic && folder_type != LLFolderType::FT_SETTINGS) { // It is a fatal problem or can lead to fatal problems for COF, - // outfits and trash and other non-automatic folders. - // Exception: FT_SETTINGS likely only deserves a warning. + // outfits, trash and other non-automatic folders. fatal_errs++; } else { // For automatic folders it's not a fatal issue and shouldn't // break inventory or other functionality further + // Exception: FT_SETTINGS is not automatic, but only deserves a warning. warnings++; } } -- cgit v1.2.3