Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET application throws System.NullReferenceException from Session.Remove implementation

We are getting random System.NullReferenceException in our ASP.NET web application. We are using inproc session state. Stacktrace:

System.NullReferenceException: Object reference not set to an instance of an object.
at System.Collections.Specialized.NameObjectCollectionBase.BaseRemove(String name)
at System.Web.SessionState.SessionStateItemCollection.Remove(String name)
at System.Web.SessionState.HttpSessionStateContainer.Remove(String name)
at System.Web.UI.SessionPageStatePersister.Save()
at System.Web.UI.Page.SaveAllState()
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

The problem seems to come from Page.PageStatePersister property which we have overriden like this.

protected override PageStatePersister PageStatePersister {
  get {
    return new SessionPageStatePersister(Page); 
  }
}

Reflector showed that SessionPageStatePersister internally calls Session.Remove.

We are getting similar random NullReferenceException while calling Session.Remove directly on Page. Relevant stacktrace:

---> System.NullReferenceException: Object reference not set to an instance of an object.
at System.Collections.Specialized.NameObjectCollectionBase.BaseRemove(String name)
at System.Web.SessionState.SessionStateItemCollection.Remove(String name)
at System.Web.SessionState.HttpSessionStateContainer.Remove(String name)
at System.Web.SessionState.HttpSessionState.Remove(String name)
at PERH.WebFramework.Bases.PageBase.OnPreInit(EventArgs e) in 

Any idea, what might cause those exceptions?

Environment:

IIS6, Windows Server 2003 64-bit, .net Framework 3.5

like image 252
user1965153 Avatar asked Nov 03 '22 07:11

user1965153


1 Answers

The issue may occur when the requests made by the same user (from the same session ID) are processed concurrently.

This is because System.Web.SessionState.SessionStateItemCollection doesn't check the entry to be null when removing it.

In the System.Web.SessionState.SessionStateItemCollection.Remove(string name) method the lock is set on the private collection _serializedItems so that Remove operation is thread safe. Yet this private collection doesn't get locked during Add operations. Considering that _serializedItems behaves as a resizing array (when entries count is >= 1/2 of its capacity the capacity is doubled and new entries are filled with nulls) concurrent addition may result into situations when null values remain in the middle of the collection. The entries only get removed from [0; entries count] range of the _serializedItems collection. When removing the entry its Key property gets accessed without null checking. Thus if null entry form the middle of the collection is removed the NullReferenceException gets cast.

By default all requests with same session ID are processed sequentially unless System.Web.Configuration.PagesSection.EnableSessionState is explicitly set to ReadOnly. In this case any operation that involves adding values into System.Web.SessionState.HttpSessionState (which internally uses System.Web.SessionState.HttpSessionStateContainer which in turn internally uses System.Web.SessionState.SessionStateItemCollection) should be properly locked to assure thread safety.

like image 128
Maria Gubenko Avatar answered Nov 11 '22 16:11

Maria Gubenko