XmlDocsExtensions.GetXmlDocsSummary(...) is called for the same member concurrently
That member inherits the documentation from a base class/interface
Internally, XmlDocsExtensions.TryGetXmlDocsDocument adds an entry to XmlDocsExtensions.Cache with documentation loaded into XElement. This is the first problematic place, because current implementation of TryGetXmlDocsDocument can return different results for the same key. Be result immutable or if every client got own unique result, then there will be no race condition.
However, there are few places which modify cached entry (XElement), by replacing with actual content without any kind of synchronization. Obviously, modifying the same XElement tree concurrently makes Linq goes nuts.
The following snippet will fail with an exception thrown by Linq implementation:
public interface IMyObject
{
/// <summary>
/// Description
/// </summary>
void DoSomething();
}
public class MyObject : IMyObject
{
/// <inheritdoc/>
public void DoSomething() { }
}
internal class Program
{
static void Do()
{
typeof(MyObject).GetMember(nameof(MyObject.DoSomething)).Single().GetXmlDocsSummary();
}
static void Main(string[] args)
{
for (int i = 0; ; ++i)
{
Console.WriteLine(i);
var tasks = new[]
{
Task.Run(Do),
Task.Run(Do),
Task.Run(Do),
Task.Run(Do),
};
Task.WaitAll(tasks);
XmlDocs.ClearCache();
}
}
}
In my case, it's about running unit-tests performing a JSON validation using JsonSchema in parallel. JsonSchema is generated on the fly.
Commit ID: 33e53f600197357307599c7536daa7715e1dbd00
Steps:
XmlDocsExtensions.GetXmlDocsSummary(...)
is called for the same member concurrentlyXmlDocsExtensions.TryGetXmlDocsDocument
adds an entry toXmlDocsExtensions.Cache
with documentation loaded into XElement. This is the first problematic place, because current implementation ofTryGetXmlDocsDocument
can return different results for the same key. Be result immutable or if every client got own unique result, then there will be no race condition.The following snippet will fail with an exception thrown by Linq implementation:
In my case, it's about running unit-tests performing a JSON validation using JsonSchema in parallel. JsonSchema is generated on the fly.