Skip to content

Commit 812f2f8

Browse files
Fixes NullRef exception in IIS in-proc (#22806)
1 parent 0ae7f1a commit 812f2f8

File tree

3 files changed

+62
-53
lines changed

3 files changed

+62
-53
lines changed

src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocesshandler.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ IN_PROCESS_HANDLER::NotifyDisconnect()
112112

113113
if (pManagedHttpContext != nullptr)
114114
{
115-
m_pDisconnectHandler(m_pManagedHttpContext);
115+
m_pDisconnectHandler(pManagedHttpContext);
116116
}
117117
}
118118

@@ -139,14 +139,17 @@ IN_PROCESS_HANDLER::SetManagedHttpContext(
139139
PVOID pManagedHttpContext
140140
)
141141
{
142+
bool disconnectFired = false;
143+
142144
{
143145
SRWExclusiveLock lock(m_srwDisconnectLock);
144146
m_pManagedHttpContext = pManagedHttpContext;
147+
disconnectFired = m_disconnectFired;
145148
}
146149

147-
if (m_disconnectFired && m_pManagedHttpContext != nullptr)
150+
if (disconnectFired && pManagedHttpContext != nullptr)
148151
{
149-
m_pDisconnectHandler(m_pManagedHttpContext);
152+
m_pDisconnectHandler(pManagedHttpContext);
150153
}
151154
}
152155

src/Servers/IIS/IIS/src/Core/IISHttpContext.cs

Lines changed: 54 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -119,69 +119,75 @@ internal unsafe IISHttpContext(
119119

120120
protected void InitializeContext()
121121
{
122-
_thisHandle = GCHandle.Alloc(this);
122+
// create a memory barrier between initialize and disconnect to prevent a possible
123+
// NullRef with disconnect being called before these fields have been written
124+
// disconnect aquires this lock as well
125+
lock (_abortLock)
126+
{
127+
_thisHandle = GCHandle.Alloc(this);
123128

124-
Method = GetVerb();
129+
Method = GetVerb();
125130

126-
RawTarget = GetRawUrl();
127-
// TODO version is slow.
128-
HttpVersion = GetVersion();
129-
Scheme = SslStatus != SslStatus.Insecure ? Constants.HttpsScheme : Constants.HttpScheme;
130-
KnownMethod = VerbId;
131-
StatusCode = 200;
131+
RawTarget = GetRawUrl();
132+
// TODO version is slow.
133+
HttpVersion = GetVersion();
134+
Scheme = SslStatus != SslStatus.Insecure ? Constants.HttpsScheme : Constants.HttpScheme;
135+
KnownMethod = VerbId;
136+
StatusCode = 200;
132137

133-
var originalPath = GetOriginalPath();
138+
var originalPath = GetOriginalPath();
134139

135-
if (KnownMethod == HttpApiTypes.HTTP_VERB.HttpVerbOPTIONS && string.Equals(RawTarget, "*", StringComparison.Ordinal))
136-
{
137-
PathBase = string.Empty;
138-
Path = string.Empty;
139-
}
140-
else
141-
{
142-
// Path and pathbase are unescaped by RequestUriBuilder
143-
// The UsePathBase middleware will modify the pathbase and path correctly
144-
PathBase = string.Empty;
145-
Path = originalPath;
146-
}
140+
if (KnownMethod == HttpApiTypes.HTTP_VERB.HttpVerbOPTIONS && string.Equals(RawTarget, "*", StringComparison.Ordinal))
141+
{
142+
PathBase = string.Empty;
143+
Path = string.Empty;
144+
}
145+
else
146+
{
147+
// Path and pathbase are unescaped by RequestUriBuilder
148+
// The UsePathBase middleware will modify the pathbase and path correctly
149+
PathBase = string.Empty;
150+
Path = originalPath;
151+
}
147152

148-
var cookedUrl = GetCookedUrl();
149-
QueryString = cookedUrl.GetQueryString() ?? string.Empty;
153+
var cookedUrl = GetCookedUrl();
154+
QueryString = cookedUrl.GetQueryString() ?? string.Empty;
150155

151-
RequestHeaders = new RequestHeaders(this);
152-
HttpResponseHeaders = new HeaderCollection();
153-
ResponseHeaders = HttpResponseHeaders;
156+
RequestHeaders = new RequestHeaders(this);
157+
HttpResponseHeaders = new HeaderCollection();
158+
ResponseHeaders = HttpResponseHeaders;
154159

155-
if (_options.ForwardWindowsAuthentication)
156-
{
157-
WindowsUser = GetWindowsPrincipal();
158-
if (_options.AutomaticAuthentication)
160+
if (_options.ForwardWindowsAuthentication)
159161
{
160-
User = WindowsUser;
162+
WindowsUser = GetWindowsPrincipal();
163+
if (_options.AutomaticAuthentication)
164+
{
165+
User = WindowsUser;
166+
}
161167
}
162-
}
163168

164-
MaxRequestBodySize = _options.MaxRequestBodySize;
169+
MaxRequestBodySize = _options.MaxRequestBodySize;
165170

166-
ResetFeatureCollection();
171+
ResetFeatureCollection();
167172

168-
if (!_server.IsWebSocketAvailable(_pInProcessHandler))
169-
{
170-
_currentIHttpUpgradeFeature = null;
171-
}
173+
if (!_server.IsWebSocketAvailable(_pInProcessHandler))
174+
{
175+
_currentIHttpUpgradeFeature = null;
176+
}
172177

173-
_streams = new Streams(this);
178+
_streams = new Streams(this);
174179

175-
(RequestBody, ResponseBody) = _streams.Start();
180+
(RequestBody, ResponseBody) = _streams.Start();
176181

177-
var pipe = new Pipe(
178-
new PipeOptions(
179-
_memoryPool,
180-
readerScheduler: PipeScheduler.ThreadPool,
181-
pauseWriterThreshold: PauseWriterThreshold,
182-
resumeWriterThreshold: ResumeWriterTheshold,
183-
minimumSegmentSize: MinAllocBufferSize));
184-
_bodyOutput = new OutputProducer(pipe);
182+
var pipe = new Pipe(
183+
new PipeOptions(
184+
_memoryPool,
185+
readerScheduler: PipeScheduler.ThreadPool,
186+
pauseWriterThreshold: PauseWriterThreshold,
187+
resumeWriterThreshold: ResumeWriterTheshold,
188+
minimumSegmentSize: MinAllocBufferSize));
189+
_bodyOutput = new OutputProducer(pipe);
190+
}
185191

186192
NativeMethods.HttpSetManagedContext(_pInProcessHandler, (IntPtr)_thisHandle);
187193
}

src/Servers/IIS/IIS/src/Core/IISHttpServer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ private static void OnDisconnect(IntPtr pvManagedHttpContext)
170170
try
171171
{
172172
context = (IISHttpContext)GCHandle.FromIntPtr(pvManagedHttpContext).Target;
173-
context.AbortIO(clientDisconnect: true);
173+
context?.AbortIO(clientDisconnect: true);
174174
}
175175
catch (Exception ex)
176176
{
@@ -184,7 +184,7 @@ private static NativeMethods.REQUEST_NOTIFICATION_STATUS OnAsyncCompletion(IntPt
184184
try
185185
{
186186
context = (IISHttpContext)GCHandle.FromIntPtr(pvManagedHttpContext).Target;
187-
context.OnAsyncCompletion(hr, bytes);
187+
context?.OnAsyncCompletion(hr, bytes);
188188
return NativeMethods.REQUEST_NOTIFICATION_STATUS.RQ_NOTIFICATION_PENDING;
189189
}
190190
catch (Exception ex)

0 commit comments

Comments
 (0)