You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This bug isn't really specific to XamlDirective but it's the class where I found the issue and it's the easiest to cause an issue. You can have the bug when using instances of XamlMember or of any of its descendants (In this case XamlDirective).
The bug is that XamlMember._reflector can be wrongly initialized when hitting this point from 3 threads and with very specific timing:
Here's the required timing of those 3 threads to have an invalid MemberReflector returned from MemberReflector.UnknownReflector:
Thread 1 and 2 invoke MemberReflector.UnknownReflector and find that s_UnknownReflector is null. Thread 1 assigns s_UnknownReflector to a new instance. Thread 3 invokes MemberReflector.UnknownReflector, finds that s_UnknownReflector is not null and returns s_UnknownReflector. Thread 2 assigns s_UnknownReflector to a new instance.
In this scenario thread 1 and 2 both return the same instance from MemberReflector.UnknownReflector while thread 3 returned an old instance from MemberReflector.UnknownReflector that wasn't fully initialized.
Now that I've explained how to have a partially initialized MemberReflector, here's how to have a stack overflow exception using XamlDirective:
We enter XamlDirective.Type when _reflector.Type is null which means that we enter this if block:
[Theory][InlineData("xamlNamespace","name")]publicvoidParallel_Ctor_String_String(stringxamlNamespace,string?name){Parallel.For(0,1000, i =>{vardirective=newXamlDirective(xamlNamespace,name);Assert.Equal(XamlLanguage.Object,directive.Type);});}
Run the test a couple of times and it should crash the process with a stack overflow exception.
Expected behavior
The process shouldn't crash with a stack overflow exception.
Actual behavior
The process crashes with a stack overflow exception.
Regression?
No.
Known Workarounds
None.
Impact
Can cause the process to crash or weird bugs at runtime but the chance of getting this issue in practice is extremely low. As explained in the description, it requires 3 threads with very specific timing so I think it would be very hard to hit in practice.
Configuration
.Net 9.0
Windows 11
x64
Not specific to that configuration.
Other information
No response
The text was updated successfully, but these errors were encountered:
Description
This bug isn't really specific to XamlDirective but it's the class where I found the issue and it's the easiest to cause an issue. You can have the bug when using instances of XamlMember or of any of its descendants (In this case XamlDirective).
The bug is that XamlMember._reflector can be wrongly initialized when hitting this point from 3 threads and with very specific timing:
wpf/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/XamlMember.cs
Line 154 in b08d70d
Here's the code for MemberReflector.UnknownReflector:
wpf/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/Schema/MemberReflector.cs
Lines 77 to 104 in b08d70d
Here's the required timing of those 3 threads to have an invalid MemberReflector returned from MemberReflector.UnknownReflector:
Thread 1 and 2 invoke MemberReflector.UnknownReflector and find that s_UnknownReflector is null. Thread 1 assigns s_UnknownReflector to a new instance. Thread 3 invokes MemberReflector.UnknownReflector, finds that s_UnknownReflector is not null and returns s_UnknownReflector. Thread 2 assigns s_UnknownReflector to a new instance.
In this scenario thread 1 and 2 both return the same instance from MemberReflector.UnknownReflector while thread 3 returned an old instance from MemberReflector.UnknownReflector that wasn't fully initialized.
Now that I've explained how to have a partially initialized MemberReflector, here's how to have a stack overflow exception using XamlDirective:
We enter XamlDirective.Type when _reflector.Type is null which means that we enter this if block:
wpf/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/XamlMember.cs
Lines 251 to 254 in b08d70d
In the if block it calls the virtual method XamlDirective.LookupType() which is implemented in XamlDirective to return base.Type:
wpf/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/Schema/XamlDirective.cs
Lines 185 to 189 in b08d70d
We then have an infinite loop of Type -> LookupType() -> Type -> LookupType() -> etc.
Reproduction Steps
Add this code to https://github.com/dotnet/wpf/blob/b08d70d354d9f0f34ecf4bcd5f214e57dd5dab1e/src/Microsoft.DotNet.Wpf/tests/UnitTests/System.Xaml.Tests/System/Xaml/XamlDirectiveTests.cs
Run the test a couple of times and it should crash the process with a stack overflow exception.
Expected behavior
The process shouldn't crash with a stack overflow exception.
Actual behavior
The process crashes with a stack overflow exception.
Regression?
No.
Known Workarounds
None.
Impact
Can cause the process to crash or weird bugs at runtime but the chance of getting this issue in practice is extremely low. As explained in the description, it requires 3 threads with very specific timing so I think it would be very hard to hit in practice.
Configuration
.Net 9.0
Windows 11
x64
Not specific to that configuration.
Other information
No response
The text was updated successfully, but these errors were encountered: