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)
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With