Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ninject caches an incomplete plan #360

Open
Inok opened this issue Aug 27, 2019 · 0 comments
Open

Ninject caches an incomplete plan #360

Inok opened this issue Aug 27, 2019 · 0 comments

Comments

@Inok
Copy link

Inok commented Aug 27, 2019

I found an issue with Ninject. It caches a new plan before the actual initialization (src\Ninject\Planning\Planner.cs, method CreateNewPlan).

plan = this.CreateEmptyPlan(type);
this.plans.Add(type, plan);
// ThreadAbortException happens here
this.Strategies.Map(s => s.Execute(plan));

If the thread aborts on the first activation of a class right between plan caching and initialization, it leads to the following error on the next activation attempts:

ActivationException: Error activating Foo using self-binding of Foo
No constructor was available to create an instance of the implementation type.

In our case, the issue happens with ASP.NET applications when the application was just started and a request was aborted during the first activation of a class. Since we have hundreds of registered classes and hundreds of application instances, the issue happens quite often.

Repro:

void Main()
{
	var rnd = new Random((int)DateTime.UtcNow.Ticks);
	while (true)
	{
		TryReproduce(rnd);
	}
}

void TryReproduce(Random rnd)
{
	var kernel = new StandardKernel();
	kernel.Bind<Dep>().ToSelf();
	kernel.Bind<Foo0>().ToSelf();
	kernel.Bind<Foo1>().ToSelf();
	kernel.Bind<Foo2>().ToSelf();
	kernel.Bind<Foo3>().ToSelf();
	kernel.Bind<Foo4>().ToSelf();

	int wait = 1;

	var t = new System.Threading.Thread(() =>
	{
		Volatile.Write(ref wait, 0);
		kernel.Get<Foo0>();
		kernel.Get<Foo1>();
		kernel.Get<Foo2>();
		kernel.Get<Foo3>();
		kernel.Get<Foo4>();

	});

	t.Start();

	while (Volatile.Read(ref wait) != 0) ;

	Thread.SpinWait(rnd.Next(10000, 500000));

	t.Abort();

	kernel.Get<Foo0>();
	kernel.Get<Foo1>();
	kernel.Get<Foo2>();
	kernel.Get<Foo3>();
	kernel.Get<Foo4>();

	Console.WriteLine("Ok");

}

public class Dep { public Dep() { } }
public class Foo0 { public Foo0(Dep dep) { } }
public class Foo1 { public Foo1(Dep dep) { } }
public class Foo2 { public Foo2(Dep dep) { } }
public class Foo3 { public Foo3(Dep dep) { } }
public class Foo4 { public Foo4(Dep dep) { } }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant