Skip to content

[Bug]: GetScope(HttpContextBase) recurses infinitely → StackOverflowException crashes w3wp under concurrent requests #7440

Description

@gvnrajput

Is there an existing issue for this?

  • I have searched the existing issues

What happened?

Under concurrent request load (reliably reproduced with a bulk file upload/overwrite through the Resource Manager / Digital Asset Manager), DotNetNuke.Common.Extensions.HttpContextDependencyInjectionExtensions.GetScope(HttpContextBase) calls itself with no recursion bound and never terminates. The IIS worker process crashes with a StackOverflowException (Windows exception code 0xC00000FD, uncatchable). Repeated crashes trip WAS Rapid-Fail Protection and take the whole application pool offline.

Steps to reproduce?

  1. Open a page hosting the Resource Manager (e.g. the Site Assets page).
  2. Select 100+ files whose names already exist in the target folder.
  3. Upload them, then click "Overwrite" on ~20+ of them in quick succession.
    (This fires many concurrent POST /API/InternalServices/FileUpload/UploadFromLocal requests, multiplexed over one HTTP/2 connection.)
  4. The w3wp worker crashes with a stack overflow; a new worker starts, is hit by the same load, and crashes again ~every 90s (WAS Event 5011), until the app pool is disabled and the site returns 503.

A single-file upload never triggers it; only concurrent bulk uploads do.

Current Behavior

w3wp.exe crashes with exception code 0xC00000FD (STACK_OVERFLOW), faulting module mscorlib.ni.dll. The application pool enters a kill/restart loop (WAS Event 5011 roughly every 90 seconds) and eventually goes offline (503 / AppOffline). Because a StackOverflowException cannot be caught, nothing is logged by the application itself.

Expected Behavior

Concurrent requests that need the per-request DI scope resolve it safely and deterministically, with no unbounded recursion and no process crash.

Relevant log output

Windows System log (WAS), repeating ~every 90s:
  Event 5011: A process serving application pool 'dnndev.me' suffered a fatal communication error with the Windows Process Activation Service. The process id was '...'.

Windows Application log:
  Event 1000 (Application Error): Faulting application name: w3wp.exe ... Faulting module name: mscorlib.ni.dll ... Exception code: 0xc00000fd

Managed stack of the faulting thread (dotnet-dump 'clrstack'), ~5,104 repeated frames:
  System.Collections.Hashtable.get_Item(System.Object)
  DotNetNuke.Common.Extensions.HttpContextDependencyInjectionExtensions.GetScope(System.Collections.IDictionary)
  DotNetNuke.Common.Extensions.HttpContextDependencyInjectionExtensions.GetScope(System.Web.HttpContextBase)
  DotNetNuke.Common.Extensions.HttpContextDependencyInjectionExtensions.GetScope(System.Web.HttpContextBase)
  ... (× ~5,104) ...

Anything else?

ROOT CAUSE (deterministic) — ClearScope/DisposeScope remove the scope entry but leave the "GetScope_lock" sentinel in HttpContext.Items:

public static void ClearScope(this HttpContextBase httpContext)
{
    httpContext.Items.Remove(typeof(IServiceScope));   // "GetScope_lock" is NOT removed
}
private static void DisposeScope(HttpContextBase httpContext)
{
    httpContext.Items.GetScope()?.Dispose();
    httpContext.ClearScope();
}

GetScope registers AddOnRequestCompleted(DisposeScope). After the request scope is disposed, Items[typeof(IServiceScope)] is gone but Items["GetScope_lock"] remains. Any later GetScope call then hits:
if (httpContext.Items.Contains("GetScope_lock")) return httpContext.GetScope();
and recurses forever -> StackOverflowException. Once GetScope runs after teardown, the crash is guaranteed (not a race).

OBSERVED TRIGGER (faulting-thread stack): a DI-activated service is resolved during an EndRequest module, after scope disposal:
GetScope(HttpContextBase) <- recurses 5,104x
DotNetNuke.Common.Globals.GetCurrentServiceProvider()
DotNetNuke.Entities.Modules.ModuleController..ctor(IEventLogger, IPermissionDefinitionService, IHostSettings)
DotNetNuke.Entities.Modules.ModuleController..ctor()
.ConfigurationController..ctor()
.SiteLogModule.OnEndRequest(object, EventArgs)
Constructing ModuleController via its parameterless ctor (which calls GetCurrentServiceProvider) after the scope is disposed is enough to hit this. Bulk file upload/overwrite reproduces it reliably.

MINIMAL FIX — clear the sentinel in ClearScope:
public static void ClearScope(this HttpContextBase httpContext)
{
httpContext.Items.Remove(typeof(IServiceScope));
httpContext.Items.Remove("GetScope_lock"); // add this
}

ROBUST FIX — also make the retry non-recursive and thread-safe (HttpContext.Items is a non-thread-safe Hashtable; the crash bottoms out in Hashtable.get_Item). Lock on a stable per-context monitor and re-check inside the lock instead of "return httpContext.GetScope();".

SCOPE: confirmed by decompiling DotNetNuke.dll from a 10.3.2 install; the same recursive retry + "GetScope_lock" key are still present on develop:
https://github.com/dnnsoftware/Dnn.Platform/blob/develop/DNN%20Platform/Library/Common/Extensions/HttpContextDependencyInjectionExtensions.cs

WORKAROUND for operators until fixed: avoid resolving DI-backed services after request scope disposal (e.g. in late EndRequest handlers); reduce concurrent upload requests. (Raising the ASP.NET min thread-pool size makes it worse.)

DIAGNOSED WITH:
dotnet-dump analyze w3wp.exe..dmp -c "clrthreads" -c "syncblk" -c "clrstack -all" -c "exit"
-> thread with System.StackOverflowException has ~5,104 GetScope(HttpContextBase) frames; syncblk empty (not a deadlock).

getscope-stackoverflow-callstack 1.txt

Affected Versions

10.3.3 (latest release)

What browsers are you seeing the problem on?

Chrome

Code of Conduct

  • I agree to follow this project's Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions