Skip to content

ALC aware lifetime scope throws SOE when disposed. #1437

@hemirunner426

Description

@hemirunner426

Describe the Bug

If I register a concrete class which inherits from an abstract generic class, a stack overflow exception occurs when an ALC child lifetime scope is disposed.

Steps to Reproduce

I've created a test console app which highlights this issue. It can be found here:
Scoped Lifetime Bug Repro(https://github.com/hemirunner426/autofaclifetime)

The test console project more closely resembles the project I discovered this issue in. The project I'm working on has a plugin arch to it and the plugins it loads can run code any time during the lifecycle of the application including bootstrap and shutdown.
I'm looking to ensure that those lifetime scopes are disposed of when the host shuts down.

To reproduce in the test console:

  1. Start the project.
  2. CTRL+C the console window to invoke IHostedService.StopAsync()
  3. The SOE occurs when the child scope is disposed.

NOTE: This is also reproducible if the child scope (the ALC aware lifetime scope) is disposed at any time, not just during StopAsync(). A standard child lifetime scope does not exhibit this behavior. Also, removing the generic declararion on the abstract class allows the ALC aware scope to dispose properly.

Expected Behavior

The ALC child scope disposes without an exception.

Exception with Stack Trace

   System.Collections.Generic.HashSet`1<System.Reflection.Assembly>)
   at Autofac.Util.Cache.TypeAssemblyReferenceProvider.PopulateAllReferencedAssemblies(System.Type, System.Collections.Generic.HashSet`1<System.Reflection.Assembly>)
   at Autofac.Util.Cache.TypeAssemblyReferenceProvider.PopulateAllReferencedAssemblies(System.Type, System.Collections.Generic.HashSet`1<System.Reflection.Assembly>)
   at Autofac.Util.Cache.TypeAssemblyReferenceProvider.PopulateAllReferencedAssemblies(System.Type, System.Collections.Generic.HashSet`1<System.Reflection.Assembly>)
   at Autofac.Util.Cache.TypeAssemblyReferenceProvider.PopulateAllReferencedAssemblies(System.Type, System.Collections.Generic.HashSet`1<System.Reflection.Assembly>)
   at Autofac.Util.Cache.TypeAssemblyReferenceProvider.PopulateAllReferencedAssemblies(System.Type, System.Collections.Generic.HaSystem.Collections.Generic.HashSet`1<System.Reflection.Assembly>)
   at Autofac.Util.Cache.TypeAssemblyReferenceProvider.PopulateAllReferencedAssemblies(System.Type, System.Collections.Generic.HashSet`1<System.Reflection.Assembly>)
   at Autofac.Util.Cache.TypeAssemblyReferenceProvider.PopulateAllReferencedAssemblies(System.Type, System.Collections.Generic.HashSet`1<System.Reflection.Assembly>)
   at Autofac.Util.Cache.TypeAssemblyReferenceProvider.PopulateAllReferencedAssemblies(System.Type, System.Collections.Generic.HashSet`1<System.Reflection.Assembly>)
   at Autofac.Util.Cache.TypeAssemblyReferenceProvider.PopulateAllReferencedAssemblies(System.Type, System.Collections.Generic.HashSet`1<System.Reflection.Assembly>)
   at Autofac.Util.Cache.TypeAssemblyReferenceProvider.PopulateAllReferencedAssemblies(System.Type, System.Collections.Generic.HashSet`1<System.Reflection.Assembly>)
   at Autofac.Util.Cache.TypeAssemblyReferenceProvider.PopulateAllReferencedAssemblies(System.Type, System.Collections.Generic.HashSet`1<System.Reflection.Assembly>)
   at Autofac.Util.Cache.TypeAssemblyReferenceProvider.PopulateAllReferencedAssemblies(System.Type, System.Collections.Generic.HashSet`1<System.Reflection.Assembly>)
   at Autofac.Util.Cache.TypeAssemblyReferenceProvider.PopulateAllReferencedAssemblies(System.Type, System.Collections.Generic.HashSet`1<System.Reflection.Assembly>)
   at Autofac.Util.Cache.TypeAssemblyReferenceProvider.PopulateAllReferencedAssemblies(System.Type, System.Collections.Generic.HashSet`1<System.Reflection.Assembly>)
   at Autofac.Util.Cache.TypeAssemblyReferenceProvider.PopulateAllReferencedAssemblies(System.Type, System.Collections.Generic.HashSet`1<System.Reflection.Assembly>)
   at Autofac.Util.Cache.TypeAssemblyReferenceProvider.PopulateAllReferencedAssemblies(System.Type, System.Collections.Generic.HashSet`1<System.Reflection.Assembly>)
   at Autofac.Util.Cache.TypeAssemblyReferenceProvider.PopulateAllReferencedAssemblies(System.Type, System.Collections.Generic.HashSet`1<System.Reflection.Assembly>)
   at Autofac.Util.Cache.TypeAssemblyReferenceProvider.PopulateAllReferencedAssemblies(System.Type, System.Collections.Generic.HashSet`1<System.Reflection.Assembly>)
   at Autofac.Util.Cache.TypeAssemblyReferenceProvider.PopulateAllReferencedAssemblies(System.Type, System.Collections.Generic.HashSet`1<System.Reflection.Assembly>)
   at Autofac.Util.Cache.TypeAssemblyReferenceProvider.GetAllReferencedAssemblies(System.Reflection.MemberInfo, System.Collections.Generic.HashSet`1<System.Reflection.Assembly>)
   at Autofac.Util.Cache.ReflectionCacheDictionary`2[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].Clear(Autofac.Core.ReflectionCacheClearPredicate)
   at Autofac.Core.ReflectionCacheSet.Clear(Autofac.Core.ReflectionCacheClearPredicate)
   at Autofac.Core.Lifetime.LifetimeScope+<>c__DisplayClass23_0.<BeginLoadContextLifetimeScope>b__0(System.Object, Autofac.Core.Lifetime.LifetimeScopeEndingEventArgs)
   at Autofac.Core.Lifetime.LifetimeScope+<DisposeAsync>d__46.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[Autofac.Core.Lifetime.LifetimeScope+<DisposeAsync>d__46, Autofac, Version=8.1.1.0, Culture=neutral, PublicKeyToken=17863af14b0044da]](<DisposeAsync>d__46 ByRef)
   at System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder.Start[[Autofac.Core.Lifetime.LifetimeScope+<DisposeAsync>d__46, Autofac, Version=8.1.1.0, Culture=neutral, PublicKeyToken=17863af14b0044da]](<DisposeAsync>d__46 ByRef)
   at Autofac.Core.Lifetime.LifetimeScope.DisposeAsync(Boolean)
   at Autofac.Util.Disposable.DisposeAsync()
   at AutofacLifetime.HostedService+<StopAsync>d__5.MoveNext()
   at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[[System.Threading.Tasks.VoidTaskResult, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext(System.Threading.Thread)
   at System.Runtime.CompilerServices.TaskAwaiter+<>c.<OutputWaitEtwEvents>b__12_0(System.Action, System.Threading.Tasks.Task)
   at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action, Boolean)
   at System.Threading.Tasks.Task.RunContinuations(System.Object)
   at System.Threading.Tasks.Task.TrySetResult()
   at System.Threading.Tasks.Task+DelayPromise.CompleteTimedOut()
   at System.Threading.TimerQueueTimer.Fire(Boolean)
   at System.Threading.TimerQueue.FireNextTimers()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
   at System.Threading.PortableThreadPool+WorkerThread.WorkerThreadStart()

Dependency Versions

Autofac: 8.1.1
.NET CORE; 8.0

Additional Info

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions