question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Stack overflow exception when creating second Fake of type that takes a parameter of its own type

See original GitHub issue

We are facing an issue while running the following tests:

using System;
using FakeItEasy;
using NUnit.Framework;

namespace ConsoleApp1
{
    [TestFixture]
    public class ClassTest
    {
        [SetUp]
        public void SetUp()
        {
        }

        [Test]
        public void Test1()
        {
            var fake = A.Fake<Class>();
        }

        [Test]
        public void Test2()
        {
            var fake = A.Fake<Class>();
        }
    }
    
    public class Class
    {
        public Class(Type type)
        {
        }

        public Class(Type type, Class @class)
        {
        }
    }
}

Only when they are executed together, the second test (Test2) fails with a Stack Overflow Exception. The first test instead has no problem. Until version 4.6.0 of FakeItEasy this sample works correctly.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:12 (11 by maintainers)

github_iconTop GitHub Comments

1reaction
blairconradcommented, Aug 27, 2019

I have a cause and a fix (figured out just as I was leaving the house this mornining).

Short version is:

  • we try to fake Class, which attempts to resolve Dummy parameters for each constructor, longest first.
  • making a Dummy Type is fine, so we try to make a Dummy for Class
  • the Dummy-creation logic falls back to its “make a Dummy by making a Fake” logic, which does the same sort of thing as above
  • we can make a Type as before, but when we try to make a Dummy Class, we figure out that we’re already making a Class, so we back off and try the short constructor, with just Type arguments
  • We make the Fake and in the “best constructor” cache record that the one-parameter constructor is preferred, so we never have to try all this again
  • We pop back up the stack and then make a Fake Class at the “make a Fake” level, using our Dummy Type and Dummy Class and then… we record that the two-parameter constructor is best

When we try to fake the Class the second time, we see the two-parameter constructor is best, and try to use it, resulting in stackoverflow.

If we replae https://github.com/FakeItEasy/FakeItEasy/blob/02e6f4ef3e0ae49fdd3e712dd2e523a025a94d69/src/FakeItEasy/Creation/FakeObjectCreator.cs#L214

with

this.parameterTypesCache.TryAdd(typeOfFake, parameterTypes);

The tests pass. I think this is a good change, as we could have competing construction from different threads. There may be other caches that would benefit from this sort of change.

A larger change would be to enroll Fake creation in the loop-detection mechanism that we have for creating a Dummy, but I think that amounts to a performance optimization, since it wouldn’t help with a multi-threaded problem.

I can whip a PR up (with spec) for the reported problem certainly by tomorrow, or maybe today if work allows me a few minutes.

0reactions
blairconradcommented, Aug 29, 2019

Oh, good. I ended up leaning the same way. PR incoming!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Is it possible to create a generic method that take ...
"Method group" is a concept that exists only in the language's syntax, there is no runtime type that corresponds to a method group....
Read more >
What is a stack overflow error?
A stack overflow is a type of buffer overflow error that occurs when a computer program tries to use more memory space in...
Read more >
StackOverflowException Class (System)
The exception that is thrown when the execution stack exceeds the stack size. This class cannot be inherited.
Read more >
Should my classes have separate constructors just for unit ...
I like to write classes with two constructors: a primary constructor used in production code, and a default constructor just for unit tests....
Read more >
If everyone hates it, why is OOP still so widespread?
Because objects can be created as subtypes of other objects, they can inherit variables and methods from those objects. This allows objects to ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found