Skip to content

ILTypeBuilder lazy member-wrapper caches may race under parallel F# compilation #481

@sergey-tihon

Description

@sergey-tihon

Detected inside SwaggerProvider project fsprojects/SwaggerProvider#332

After upgrading from 57d2c4f92758078fbce31976325e7661fa737104 to 32fd6037e053d5d7ed532b84b836eb92fc8784b3 (which added lazy caching for GetConstructors/GetMethods/etc. in ILTypeBuilder), intermittent FS3033 errors appear in SwaggerProvider's CI when the F# compiler invokes type providers from parallel compilation threads:

  • Ubuntu: InvalidOperationException: Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state.CI run 23313927434
  • Windows: NullReferenceExceptionCI run 23350007356

Hypothesis: The lazy values ctorDefs/methDefs/etc. are defined per ILTypeBuilder instance and bound to this. The F# compiler can call GetConstructors(bf)/GetMethods(bf) on the same ILTypeBuilder from multiple threads when compiling a project file that has multiple type-provider instantiations. If two threads call ctorDefs.Force() while inp.Methods.Entries is being iterated, the race on the underlying mutable inp data structure produces the above exceptions.

The previous code (57d2c4f9) created a fresh array on each GetConstructors call (no shared state), which avoided this race.

Repro project: fsprojects/SwaggerProvider (see PR #331).
Affected SDK commit: 32fd6037 (unchanged through 821de018).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions