Skip to content

Commit

Permalink
Originally a race condition exists in CheckDefaultProvider and leads
Browse files Browse the repository at this point in the history
to wrong results when many methods are called simultaneously.

The PR fixes that by extending the lock statement.

Fix dotnet#92394
  • Loading branch information
karakasa committed Sep 23, 2023
1 parent a8a259c commit e4c4296
Showing 1 changed file with 22 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ private bool Error
set => Interlocked.Exchange(ref _error, value ? 1 : 0);
}

private void ConcurrentTest(SomeType instance)
private void ConcurrentTest(TypeWithProperty instance)
{
var properties = TypeDescriptor.GetProperties(instance);
Thread.Sleep(10);
Expand All @@ -39,10 +39,10 @@ public void GetProperties_ReturnsExpected()

using var finished = new CountdownEvent(concurrentCount);

var instances = new SomeType[concurrentCount];
var instances = new TypeWithProperty[concurrentCount];
for (int i = 0; i < concurrentCount; i++)
{
instances[i] = new SomeType();
instances[i] = new TypeWithProperty();
}

for (int i = 0; i < concurrentCount; i++)
Expand All @@ -63,50 +63,48 @@ public void GetProperties_ReturnsExpected()
}
else
{
Assert.False(Error, "Fallback type descriptor is used.");
Assert.False(Error, "Fallback type descriptor is used. Possible race condition.");
}
}

private class SomeTypeProvider : TypeDescriptionProvider
public sealed class EmptyPropertiesTypeProvider : TypeDescriptionProvider
{
public static ThreadLocal<bool> Constructed = new ThreadLocal<bool>();
public static ThreadLocal<bool> GetPropertiesCalled = new ThreadLocal<bool>();
private class CTD : ICustomTypeDescriptor
private sealed class EmptyPropertyListDescriptor : ICustomTypeDescriptor
{
public AttributeCollection GetAttributes() => AttributeCollection.Empty;

public string? GetClassName() => null;

public string? GetComponentName() => null;
public TypeConverter GetConverter() => new TypeConverter();

public TypeConverter? GetConverter() => new TypeConverter();

public EventDescriptor? GetDefaultEvent() => null;

public PropertyDescriptor? GetDefaultProperty() => null;

public object? GetEditor(Type editorBaseType) => null;

public EventDescriptorCollection GetEvents() => EventDescriptorCollection.Empty;
public EventDescriptorCollection GetEvents(Attribute[]? attributes) => EventDescriptorCollection.Empty;

public PropertyDescriptorCollection GetProperties()
{
GetPropertiesCalled.Value = true;
return PropertyDescriptorCollection.Empty;
}
public EventDescriptorCollection GetEvents(Attribute[]? attributes) => GetEvents();

public PropertyDescriptorCollection GetProperties(Attribute[]? attributes)
{
throw new NotImplementedException();
}
public PropertyDescriptorCollection GetProperties() => PropertyDescriptorCollection.Empty;

public PropertyDescriptorCollection GetProperties(Attribute[]? attributes) => GetProperties();

public object? GetPropertyOwner(PropertyDescriptor? pd) => null;
}
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object? instance)
{
Constructed.Value = true;
return new CTD();
return new EmptyPropertyListDescriptor();
}
}

[TypeDescriptionProvider(typeof(SomeTypeProvider))]
private sealed class SomeType
[TypeDescriptionProvider(typeof(EmptyPropertiesTypeProvider))]
public sealed class TypeWithProperty
{
public int SomeProperty { get; set; }
public int OneProperty { get; set; }
}
}
}

0 comments on commit e4c4296

Please sign in to comment.