SL-15711 Viewer hangs with agents with malformed inventory
parent
be577ac575
commit
830cd677ff
|
|
@ -3742,17 +3742,18 @@ void LLInventoryModel::dumpInventory() const
|
|||
// returning an overall good/bad flag.
|
||||
bool LLInventoryModel::validate() const
|
||||
{
|
||||
bool valid = true;
|
||||
const S32 MAX_VERBOSE_ERRORS = 40; // too many errors can cause disconect or freeze
|
||||
S32 error_count = 0;
|
||||
|
||||
if (getRootFolderID().isNull())
|
||||
{
|
||||
LL_WARNS() << "no root folder id" << LL_ENDL;
|
||||
valid = false;
|
||||
error_count++;
|
||||
}
|
||||
if (getLibraryRootFolderID().isNull())
|
||||
{
|
||||
LL_WARNS() << "no root folder id" << LL_ENDL;
|
||||
valid = false;
|
||||
error_count++;
|
||||
}
|
||||
|
||||
if (mCategoryMap.size() + 1 != mParentChildCategoryTree.size())
|
||||
|
|
@ -3760,7 +3761,7 @@ bool LLInventoryModel::validate() const
|
|||
// ParentChild should be one larger because of the special entry for null uuid.
|
||||
LL_INFOS() << "unexpected sizes: cat map size " << mCategoryMap.size()
|
||||
<< " parent/child " << mParentChildCategoryTree.size() << LL_ENDL;
|
||||
valid = false;
|
||||
error_count++;
|
||||
}
|
||||
S32 cat_lock = 0;
|
||||
S32 item_lock = 0;
|
||||
|
|
@ -3772,23 +3773,32 @@ bool LLInventoryModel::validate() const
|
|||
const LLViewerInventoryCategory *cat = cit->second;
|
||||
if (!cat)
|
||||
{
|
||||
LL_WARNS() << "invalid cat" << LL_ENDL;
|
||||
valid = false;
|
||||
if (error_count < MAX_VERBOSE_ERRORS)
|
||||
{
|
||||
LL_WARNS() << "invalid cat" << LL_ENDL;
|
||||
}
|
||||
error_count++;
|
||||
continue;
|
||||
}
|
||||
if (cat_id != cat->getUUID())
|
||||
{
|
||||
LL_WARNS() << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL;
|
||||
valid = false;
|
||||
if (error_count < MAX_VERBOSE_ERRORS)
|
||||
{
|
||||
LL_WARNS() << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL;
|
||||
}
|
||||
error_count++;
|
||||
}
|
||||
|
||||
if (cat->getParentUUID().isNull())
|
||||
{
|
||||
if (cat_id != getRootFolderID() && cat_id != getLibraryRootFolderID())
|
||||
{
|
||||
LL_WARNS() << "cat " << cat_id << " has no parent, but is not root ("
|
||||
<< getRootFolderID() << ") or library root ("
|
||||
<< getLibraryRootFolderID() << ")" << LL_ENDL;
|
||||
if (error_count < MAX_VERBOSE_ERRORS)
|
||||
{
|
||||
LL_WARNS() << "cat " << cat_id << " has no parent, but is not root ("
|
||||
<< getRootFolderID() << ") or library root ("
|
||||
<< getLibraryRootFolderID() << ")" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
cat_array_t* cats;
|
||||
|
|
@ -3796,8 +3806,11 @@ bool LLInventoryModel::validate() const
|
|||
getDirectDescendentsOf(cat_id,cats,items);
|
||||
if (!cats || !items)
|
||||
{
|
||||
LL_WARNS() << "invalid direct descendents for " << cat_id << LL_ENDL;
|
||||
valid = false;
|
||||
if (error_count < MAX_VERBOSE_ERRORS)
|
||||
{
|
||||
LL_WARNS() << "invalid direct descendents for " << cat_id << LL_ENDL;
|
||||
}
|
||||
error_count++;
|
||||
continue;
|
||||
}
|
||||
if (cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN)
|
||||
|
|
@ -3806,12 +3819,15 @@ bool LLInventoryModel::validate() const
|
|||
}
|
||||
else if (cats->size() + items->size() != cat->getDescendentCount())
|
||||
{
|
||||
LL_WARNS() << "invalid desc count for " << cat_id << " name [" << cat->getName()
|
||||
<< "] parent " << cat->getParentUUID()
|
||||
<< " cached " << cat->getDescendentCount()
|
||||
<< " expected " << cats->size() << "+" << items->size()
|
||||
<< "=" << cats->size() +items->size() << LL_ENDL;
|
||||
valid = false;
|
||||
if (error_count < MAX_VERBOSE_ERRORS)
|
||||
{
|
||||
LL_WARNS() << "invalid desc count for " << cat_id << " name [" << cat->getName()
|
||||
<< "] parent " << cat->getParentUUID()
|
||||
<< " cached " << cat->getDescendentCount()
|
||||
<< " expected " << cats->size() << "+" << items->size()
|
||||
<< "=" << cats->size() + items->size() << LL_ENDL;
|
||||
}
|
||||
error_count++;
|
||||
}
|
||||
if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)
|
||||
{
|
||||
|
|
@ -3831,8 +3847,11 @@ bool LLInventoryModel::validate() const
|
|||
|
||||
if (!item)
|
||||
{
|
||||
LL_WARNS() << "null item at index " << i << " for cat " << cat_id << LL_ENDL;
|
||||
valid = false;
|
||||
if (error_count < MAX_VERBOSE_ERRORS)
|
||||
{
|
||||
LL_WARNS() << "null item at index " << i << " for cat " << cat_id << LL_ENDL;
|
||||
}
|
||||
error_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -3840,10 +3859,13 @@ bool LLInventoryModel::validate() const
|
|||
|
||||
if (item->getParentUUID() != cat_id)
|
||||
{
|
||||
LL_WARNS() << "wrong parent for " << item_id << " found "
|
||||
<< item->getParentUUID() << " expected " << cat_id
|
||||
<< LL_ENDL;
|
||||
valid = false;
|
||||
if (error_count < MAX_VERBOSE_ERRORS)
|
||||
{
|
||||
LL_WARNS() << "wrong parent for " << item_id << " found "
|
||||
<< item->getParentUUID() << " expected " << cat_id
|
||||
<< LL_ENDL;
|
||||
}
|
||||
error_count++;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -3851,17 +3873,24 @@ bool LLInventoryModel::validate() const
|
|||
item_map_t::const_iterator it = mItemMap.find(item_id);
|
||||
if (it == mItemMap.end())
|
||||
{
|
||||
LL_WARNS() << "item " << item_id << " found as child of "
|
||||
<< cat_id << " but not in top level mItemMap" << LL_ENDL;
|
||||
valid = false;
|
||||
|
||||
if (error_count < MAX_VERBOSE_ERRORS)
|
||||
{
|
||||
LL_WARNS() << "item " << item_id << " found as child of "
|
||||
<< cat_id << " but not in top level mItemMap" << LL_ENDL;
|
||||
}
|
||||
error_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
LLViewerInventoryItem *top_item = it->second;
|
||||
if (top_item != item)
|
||||
{
|
||||
LL_WARNS() << "item mismatch, item_id " << item_id
|
||||
<< " top level entry is different, uuid " << top_item->getUUID() << LL_ENDL;
|
||||
if (error_count < MAX_VERBOSE_ERRORS)
|
||||
{
|
||||
LL_WARNS() << "item mismatch, item_id " << item_id
|
||||
<< " top level entry is different, uuid " << top_item->getUUID() << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3870,19 +3899,25 @@ bool LLInventoryModel::validate() const
|
|||
bool found = getObjectTopmostAncestor(item_id, topmost_ancestor_id);
|
||||
if (!found)
|
||||
{
|
||||
LL_WARNS() << "unable to find topmost ancestor for " << item_id << LL_ENDL;
|
||||
valid = false;
|
||||
if (error_count < MAX_VERBOSE_ERRORS)
|
||||
{
|
||||
LL_WARNS() << "unable to find topmost ancestor for " << item_id << LL_ENDL;
|
||||
}
|
||||
error_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (topmost_ancestor_id != getRootFolderID() &&
|
||||
topmost_ancestor_id != getLibraryRootFolderID())
|
||||
{
|
||||
LL_WARNS() << "unrecognized top level ancestor for " << item_id
|
||||
<< " got " << topmost_ancestor_id
|
||||
<< " expected " << getRootFolderID()
|
||||
<< " or " << getLibraryRootFolderID() << LL_ENDL;
|
||||
valid = false;
|
||||
if (error_count < MAX_VERBOSE_ERRORS)
|
||||
{
|
||||
LL_WARNS() << "unrecognized top level ancestor for " << item_id
|
||||
<< " got " << topmost_ancestor_id
|
||||
<< " expected " << getRootFolderID()
|
||||
<< " or " << getLibraryRootFolderID() << LL_ENDL;
|
||||
}
|
||||
error_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3896,9 +3931,12 @@ bool LLInventoryModel::validate() const
|
|||
getDirectDescendentsOf(parent_id,cats,items);
|
||||
if (!cats)
|
||||
{
|
||||
LL_WARNS() << "cat " << cat_id << " name [" << cat->getName()
|
||||
<< "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL;
|
||||
valid = false;
|
||||
if (error_count < MAX_VERBOSE_ERRORS)
|
||||
{
|
||||
LL_WARNS() << "cat " << cat_id << " name [" << cat->getName()
|
||||
<< "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL;
|
||||
}
|
||||
error_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -3914,8 +3952,11 @@ bool LLInventoryModel::validate() const
|
|||
}
|
||||
if (!found)
|
||||
{
|
||||
LL_WARNS() << "cat " << cat_id << " name [" << cat->getName()
|
||||
<< "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL;
|
||||
if (error_count < MAX_VERBOSE_ERRORS)
|
||||
{
|
||||
LL_WARNS() << "cat " << cat_id << " name [" << cat->getName()
|
||||
<< "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3927,24 +3968,33 @@ bool LLInventoryModel::validate() const
|
|||
LLViewerInventoryItem *item = iit->second;
|
||||
if (item->getUUID() != item_id)
|
||||
{
|
||||
LL_WARNS() << "item_id " << item_id << " does not match " << item->getUUID() << LL_ENDL;
|
||||
valid = false;
|
||||
if (error_count < MAX_VERBOSE_ERRORS)
|
||||
{
|
||||
LL_WARNS() << "item_id " << item_id << " does not match " << item->getUUID() << LL_ENDL;
|
||||
}
|
||||
error_count++;
|
||||
}
|
||||
|
||||
const LLUUID& parent_id = item->getParentUUID();
|
||||
if (parent_id.isNull())
|
||||
{
|
||||
LL_WARNS() << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL;
|
||||
if (error_count < MAX_VERBOSE_ERRORS)
|
||||
{
|
||||
LL_WARNS() << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (error_count < MAX_VERBOSE_ERRORS)
|
||||
{
|
||||
cat_array_t* cats;
|
||||
item_array_t* items;
|
||||
getDirectDescendentsOf(parent_id,cats,items);
|
||||
if (!items)
|
||||
{
|
||||
LL_WARNS() << "item " << item_id << " name [" << item->getName()
|
||||
<< "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL;
|
||||
if (error_count < MAX_VERBOSE_ERRORS)
|
||||
{
|
||||
LL_WARNS() << "item " << item_id << " name [" << item->getName()
|
||||
<< "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -3959,63 +4009,70 @@ bool LLInventoryModel::validate() const
|
|||
}
|
||||
if (!found)
|
||||
{
|
||||
LL_WARNS() << "item " << item_id << " name [" << item->getName()
|
||||
<< "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL;
|
||||
if (error_count < MAX_VERBOSE_ERRORS)
|
||||
{
|
||||
LL_WARNS() << "item " << item_id << " name [" << item->getName()
|
||||
<< "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// Link checking
|
||||
if (item->getIsLinkType())
|
||||
{
|
||||
const LLUUID& link_id = item->getUUID();
|
||||
const LLUUID& target_id = item->getLinkedUUID();
|
||||
LLViewerInventoryItem *target_item = getItem(target_id);
|
||||
LLViewerInventoryCategory *target_cat = getCategory(target_id);
|
||||
// Linked-to UUID should have back reference to this link.
|
||||
if (!hasBacklinkInfo(link_id, target_id))
|
||||
{
|
||||
LL_WARNS() << "link " << item->getUUID() << " type " << item->getActualType()
|
||||
<< " missing backlink info at target_id " << target_id
|
||||
<< LL_ENDL;
|
||||
}
|
||||
// Links should have referents.
|
||||
if (item->getActualType() == LLAssetType::AT_LINK && !target_item)
|
||||
{
|
||||
LL_WARNS() << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL;
|
||||
}
|
||||
else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER && !target_cat)
|
||||
{
|
||||
LL_WARNS() << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL;
|
||||
}
|
||||
if (target_item && target_item->getIsLinkType())
|
||||
{
|
||||
LL_WARNS() << "link " << item->getName() << " references a link item "
|
||||
<< target_item->getName() << " " << target_item->getUUID() << LL_ENDL;
|
||||
}
|
||||
|
||||
// Links should not have backlinks.
|
||||
std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(link_id);
|
||||
if (range.first != range.second)
|
||||
{
|
||||
LL_WARNS() << "Link item " << item->getName() << " has backlinks!" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check the backlinks of a non-link item.
|
||||
const LLUUID& target_id = item->getUUID();
|
||||
std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(target_id);
|
||||
for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it)
|
||||
{
|
||||
const LLUUID& link_id = it->second;
|
||||
LLViewerInventoryItem *link_item = getItem(link_id);
|
||||
if (!link_item || !link_item->getIsLinkType())
|
||||
{
|
||||
LL_WARNS() << "invalid backlink from target " << item->getName() << " to " << link_id << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Link checking
|
||||
if (error_count < MAX_VERBOSE_ERRORS)
|
||||
{
|
||||
if (item->getIsLinkType())
|
||||
{
|
||||
const LLUUID& link_id = item->getUUID();
|
||||
const LLUUID& target_id = item->getLinkedUUID();
|
||||
LLViewerInventoryItem *target_item = getItem(target_id);
|
||||
LLViewerInventoryCategory *target_cat = getCategory(target_id);
|
||||
// Linked-to UUID should have back reference to this link.
|
||||
if (!hasBacklinkInfo(link_id, target_id))
|
||||
{
|
||||
LL_WARNS() << "link " << item->getUUID() << " type " << item->getActualType()
|
||||
<< " missing backlink info at target_id " << target_id
|
||||
<< LL_ENDL;
|
||||
}
|
||||
// Links should have referents.
|
||||
if (item->getActualType() == LLAssetType::AT_LINK && !target_item)
|
||||
{
|
||||
LL_WARNS() << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL;
|
||||
}
|
||||
else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER && !target_cat)
|
||||
{
|
||||
LL_WARNS() << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL;
|
||||
}
|
||||
if (target_item && target_item->getIsLinkType())
|
||||
{
|
||||
LL_WARNS() << "link " << item->getName() << " references a link item "
|
||||
<< target_item->getName() << " " << target_item->getUUID() << LL_ENDL;
|
||||
}
|
||||
|
||||
// Links should not have backlinks.
|
||||
std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(link_id);
|
||||
if (range.first != range.second)
|
||||
{
|
||||
LL_WARNS() << "Link item " << item->getName() << " has backlinks!" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check the backlinks of a non-link item.
|
||||
const LLUUID& target_id = item->getUUID();
|
||||
std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(target_id);
|
||||
for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it)
|
||||
{
|
||||
const LLUUID& link_id = it->second;
|
||||
LLViewerInventoryItem *link_item = getItem(link_id);
|
||||
if (!link_item || !link_item->getIsLinkType())
|
||||
{
|
||||
LL_WARNS() << "invalid backlink from target " << item->getName() << " to " << link_id << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cat_lock > 0 || item_lock > 0)
|
||||
|
|
@ -4032,9 +4089,9 @@ bool LLInventoryModel::validate() const
|
|||
LL_INFOS() << "Found " << version_unknown_count << " cats with unknown version" << LL_ENDL;
|
||||
}
|
||||
|
||||
LL_INFOS() << "Validate done, valid = " << (U32) valid << LL_ENDL;
|
||||
LL_INFOS() << "Validate done, found " << error_count << " errors" << LL_ENDL;
|
||||
|
||||
return valid;
|
||||
return error_count == 0;
|
||||
}
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Reference in New Issue