Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Index Out Of Bounds on List.Contains

Tags:

c#

A piece of code in the CMS I'm using (DNN) throws the following exception:

"Index was outside the bounds of the array."

With the stacktrace saying:

 at System.Collections.Generic.List`1.Contains(T item)

It is an issue that only happens sometimes (I suspect it has something to do with the cache getting broken) and only in production. This means I can't consistently reproduce it. I'm mostly interested in how it might happen.

How is it possible that a call to 'Contains' triggers an index out of bounds?

Extra info

The code calling the Contains works the following way (I've simplified the code to make the important parts more readable. The links lead to the exact classes and linenumbers)

CustomUrlDictController.cs

 List<int> urlPortals;
 var cc = new CacheController();
 cc.GetFriendlyUrlIndexFromCache(out urlPortals);
 var boolean = urlPortals.Contains(portalId); // This is where the exception happens.

CacheController.cs

void GetFriendlyUrlIndexFromCache(out List<int> urlPortals)
{
    urlPortals = null;
    object rawPortals = DataCache.GetCache(UrlPortalsKey);
    if (rawPortals != null)
    {
        urlPortals = (List<int>)rawPortals;
    }
}

DataCache (1, 2)

object GetCache(string CacheKey)
{
    return Cache[cacheKey];
}

Full stack trace

InnerMessage:Index was outside the bounds of the array.
InnerStackTrace:
at System.Collections.Generic.List`1.Contains(T item)
   at DotNetNuke.Entities.Urls.CustomUrlDictController.FetchCustomUrlDictionary(Int32 portalId, Boolean forceRebuild, Boolean bypassCache, FriendlyUrlSettings settings, SharedDictionary`2& customAliasForTabs, Guid parentTraceId)
   at DotNetNuke.Entities.Urls.TabPathHelper.GetTabPath(TabInfo tab, FriendlyUrlSettings settings, FriendlyUrlOptions options, Boolean ignoreCustomRedirects, Boolean homePageSiteRoot, Boolean isHomeTab, String cultureCode, Boolean isDefaultCultureCode, Boolean hasPath, Boolean& dropLangParms, String& customHttpAlias, Boolean& isCustomPath, Guid parentTraceId)
   at DotNetNuke.Entities.Urls.AdvancedFriendlyUrlProvider.ImproveFriendlyUrlWithMessages(TabInfo tab, String friendlyPath, String pageName, PortalSettings portalSettings, Boolean ignoreCustomRedirects, FriendlyUrlSettings settings, List`1& messages, Boolean cultureSpecificAlias, Guid parentTraceId)
   at DotNetNuke.Entities.Urls.AdvancedFriendlyUrlProvider.ImproveFriendlyUrl(TabInfo tab, String friendlyPath, String pageName, PortalSettings portalSettings, Boolean ignoreCustomRedirects, Boolean cultureSpecificAlias, FriendlyUrlSettings settings, Guid parentTraceId)
   at DotNetNuke.Entities.Urls.AdvancedFriendlyUrlProvider.FriendlyUrlInternal(TabInfo tab, String path, String pageName, String portalAlias, PortalSettings portalSettings)
   at DotNetNuke.Entities.Urls.AdvancedFriendlyUrlProvider.FriendlyUrl(TabInfo tab, String path, String pageName, PortalSettings portalSettings)
   at DotNetNuke.Services.Url.FriendlyUrl.DNNFriendlyUrlProvider.FriendlyUrl(TabInfo tab, String path, String pageName, PortalSettings settings)
   at DotNetNuke.Common.Globals.NavigateURL(Int32 tabID, Boolean isSuperTab, PortalSettings settings, String controlKey, String language, String pageName, String[] additionalParameters)
   at DotNetNuke.Common.Globals.NavigateURL(Int32 tabID, String controlKey, String[] additionalParameters)
   at Ventrian.SimpleGallery.RandomPhoto.GetAlbumUrl(String albumID)
   at Ventrian.SimpleGallery.RandomPhoto.BindPhoto(PlaceHolder phPhoto, PhotoInfo objPhoto)
   at Ventrian.SimpleGallery.RandomPhoto.dlGallery_OnItemDataBound(Object sender, DataListItemEventArgs e)
   at System.Web.UI.WebControls.DataList.OnItemDataBound(DataListItemEventArgs e)
   at System.Web.UI.WebControls.DataList.CreateItem(Int32 itemIndex, ListItemType itemType, Boolean dataBind, Object dataItem)
   at System.Web.UI.WebControls.DataList.CreateControlHierarchy(Boolean useDataSource)
   at System.Web.UI.WebControls.BaseDataList.OnDataBinding(EventArgs e)
   at System.Web.UI.WebControls.BaseDataList.DataBind()
   at Ventrian.SimpleGallery.RandomPhoto.Page_Load(Object sender, EventArgs e)
like image 675
Thijs ter Haar Avatar asked May 11 '17 12:05

Thijs ter Haar


2 Answers

Since you only want to know how Contains can cause an out of bounds exception, here's how.

This is how Contains is implemented:

source taken from http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,cf7f4095e4de7646

public bool Contains(T item) {
            if ((Object) item == null) {
                for(int i=0; i<_size; i++)
                    if ((Object) _items[i] == null)
                        return true;
                return false;
            }
            else {
                EqualityComparer<T> c = EqualityComparer<T>.Default;
                for(int i=0; i<_size; i++) {
                    if (c.Equals(_items[i], item)) return true;
                }
                return false;
            }
        }

When size is incorrect somehow (race condition?) the exception will be thrown on the internal array access

like image 97
Serve Laurijssen Avatar answered Oct 03 '22 21:10

Serve Laurijssen


I have a pull request open with a fix to this issue within DNN. We were experiencing this issue, and after making the change we have not seen this stack trace in our error logs.

https://github.com/dnnsoftware/Dnn.Platform/pull/1932

like image 42
Adam Bartholomew Avatar answered Oct 03 '22 19:10

Adam Bartholomew