Washi1337/AsmResolver

[.NET] TypeDefinition.Fields (and possibly other member getters) isn't thread-safe

Closed this issue · 3 comments

Describe the bug

As discussed in discord, calling

moduleDef.GetAllTypes().AsParallel().SelectMany(t => t.Fields).Count();

Throws the following exception

System.BadImageFormatException: Field 0400016E is not in the range of a declaring type.
   at AsmResolver.ThrowErrorListener.RegisterException(Exception exception)
   at AsmResolver.DotNet.Serialized.SerializedFieldDefinition.GetDeclaringType()
   at AsmResolver.LazyVariable`1.InitializeValue()
   at AsmResolver.DotNet.FieldDefinition.AsmResolver.Collections.IOwnedCollectionElement<AsmResolver.DotNet.TypeDefinition>.get_Owner()
   at AsmResolver.Collections.OwnedCollection`2.AssertNotNullAndHasNoOwner(TItem item)
   at AsmResolver.Collections.OwnedCollection`2.OnInsertItem(Int32 index, TItem item)
   at AsmResolver.DotNet.Serialized.SerializedTypeDefinition.CreateMemberCollection[TMember](MetadataRange range)
   at AsmResolver.DotNet.Serialized.SerializedTypeDefinition.GetFields()
   at AsmResolver.DotNet.TypeDefinition.get_Fields()
   at System.Linq.Parallel.SelectManyQueryOperator`3.SelectManyQueryOperatorEnumerator`1.MoveNext(TOutput& currentElement, Pair`2& currentKey)

While calling the same thing without the AsParallel() works as expected.

To Reproduce

Load a module, and call moduleDef.GetAllTypes().AsParallel().SelectMany(t => t.Fields).Count(). As this is a thread-safety issue, it's possible you may have to call it multiple times to reproduce the issue.

Expected behavior

The total number of field definitions in the module is returned, but (hopefully) faster than doing so single-threaded.

Screenshots

N/A

Platform

  • OS: Windows 11
  • AsmResolver Version: 4.9.0

Additional context
N/A

Potential fix has been pushed in #300. Could you verify this indeed solves the issue?

Yep, that seems to fix the issue.

Perfect. Thanks for spotting.