Skip to content

Commit a23d045

Browse files
agockeCopilot
andauthored
Fix circular init in AOT equality comparer causing NRE on Mono (#73)
The defaultComparer field in AssertEqualityComparer (AOT path) eagerly creates AssertEqualityComparerAdapter<object>, which triggers AssertEqualityComparer<object>'s static initializer. That initializer reads defaultComparer back via GetDefaultInnerComparer before the field has been assigned. On Mono/WASM this results in DefaultInnerComparer being permanently null, leading to NullReferenceException when comparing value types via IStructuralEquatable. Fix by creating a new instance on each call, matching the non-AOT reflection path behavior. Port of dotnet/arcade#16615 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 6ce8f86 commit a23d045

File tree

1 file changed

+9
-4
lines changed

1 file changed

+9
-4
lines changed

Sdk/AssertEqualityComparer_aot.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,18 @@ namespace Xunit.Sdk
1818
{
1919
partial class AssertEqualityComparer
2020
{
21-
static readonly IEqualityComparer defaultComparer = new AssertEqualityComparerAdapter<object>(new AssertEqualityComparer<object>());
22-
21+
// Create a new instance each call (matching the non-AOT/reflection path behavior)
22+
// rather than caching in a static field. A cached static field causes a circular
23+
// static initialization dependency: the field initializer triggers
24+
// AssertEqualityComparer<object>'s static initializer, which reads the field back
25+
// via GetDefaultInnerComparer before it has been assigned. On Mono/WASM, this
26+
// causes DefaultInnerComparer to be permanently null, leading to
27+
// NullReferenceException when comparing value types via IStructuralEquatable.
2328
internal static IEqualityComparer GetDefaultComparer(Type _) =>
24-
defaultComparer;
29+
new AssertEqualityComparerAdapter<object>(new AssertEqualityComparer<object>());
2530

2631
internal static IEqualityComparer GetDefaultInnerComparer(Type _) =>
27-
defaultComparer;
32+
new AssertEqualityComparerAdapter<object>(new AssertEqualityComparer<object>());
2833
}
2934

3035
partial class AssertEqualityComparer<T>

0 commit comments

Comments
 (0)