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

Creating a map for a type with a circular reference causes a stack overflow #2316

Open
Gerfatz opened this issue Jan 17, 2025 · 0 comments
Open
Labels

Comments

@Gerfatz
Copy link

Gerfatz commented Jan 17, 2025

Describe the bug
When CsvHelper tries to auto map a type that references itself, it can run into a stack overflow. This happens only under certail conditions. The self referential property needs to be declared after another property that requires mapping.

To Reproduce

using System.Globalization;
using CsvHelper;

public class MyTypedId
{
	public Guid Value { get; set; }
}

public sealed class MyClass
{
	public MyTypedId Id { get; set; }
	public MyClass Parent { get; set; }
}

public class Program
{
	public static void Main(string[] args)
	{
		var buffer = new BufferedStream(new MemoryStream());
		var csvWriter = new CsvWriter(new StreamWriter(buffer), CultureInfo.InvariantCulture);
		var context = new CsvContext(csvWriter);
		var type = typeof(MyClass);
		context.AutoMap(type);
	}
}

Changing MyClass in the above example to either of the following does not produce a stack overflow:

public sealed class MyClass
{
	public MyClass Parent { get; set; }
	public MyTypedId Id { get; set; }
}
public sealed class MyClass
{
	public Guid Id { get; set; }
	public MyClass Parent { get; set; }
}

Expected behavior
Creating a class map should not result in a stack overflow. It should detect the recursion an stop, or throw an exception.

Screenshots
If applicable, add screenshots to help explain your problem.

Additional context
I already started looking into what could be the causes of this. ClassMap.cs line 403 looks like the likely culprit to me. During mapping of the example provided, mapParents contains two entries for MyClass. One for the type being mapped, the other for the property. When the Id property gets evaluated, mapParents.Find(type) returns the first node. mapParents.Drop then drops both entries, though in this case it should only drop the second node. This explains why no stack overflow occurs when the proprties in MyClass are flipped.

Either changing Find to FindLast or keeping a reference to the node from when it was added fixes the issue. I can however not tell wheter this has implications on some other use case. If i get the time during the weekend I would fix this myself.

@Gerfatz Gerfatz added the bug label Jan 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant