Skip to content

Add GC.AllocateUninitializedArray<T> polyfill#541

Merged
SimonCropp merged 3 commits intoSimonCropp:mainfrom
paulomorgado:gc-allocate-uninitialized-array
Apr 19, 2026
Merged

Add GC.AllocateUninitializedArray<T> polyfill#541
SimonCropp merged 3 commits intoSimonCropp:mainfrom
paulomorgado:gc-allocate-uninitialized-array

Conversation

@paulomorgado
Copy link
Copy Markdown
Contributor

Summary

Add source-compatible polyfill for GC.AllocateUninitializedArray(int, bool) which was introduced in .NET 5.0.

On older runtimes the implementation delegates to
ew T[length] (zero-initialized) for source compliance — code that calls this API compiles and runs correctly on all targets, though without the performance benefit of skipping zero-initialization.

Guard

#if !NET5_0_OR_GREATER — the native API exists from .NET 5.0 onward.

Changes

  • src/Polyfill/GCPolyfill.cs — Canonical polyfill implementation
  • src/Tests/GCPolyfillTests.cs — TUnit tests
  • src/Consume/Consume.cs — Compile-time consume coverage
  • api_list.include.md — Updated API list
  • src/Split/{tfm}/GCPolyfill.cs — Per-TFM split copies

Add source-compatible polyfill for GC.AllocateUninitializedArray<T>(int, bool)
which was introduced in .NET 5.0. On older runtimes the implementation
delegates to new T[length] (zero-initialized) for source compliance.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@SimonCropp SimonCropp added this to the 10.4.0 milestone Apr 13, 2026
@SimonCropp
Copy link
Copy Markdown
Owner

I think pinned: true is problematic. It can't actually be polyfilled — the Pinned Object Heap is a runtime feature that landed in .NET 5, it's a region of the native GC heap, not some managed API hiding behind a private modifier.

silently ignoring it is pretty dangerous. The whole reason people pass pinned: true is to stash a pointer into the buffer and hand it off to native code for later (async I/O, native callbacks, long-running workers). On net5+ that's fine because POH arrays never move. With this polyfill the GC is free to relocate the array on the next compaction and the stored pointer is now aimed at whatever happens to live at that address — heap corruption that usually crashes far away from the actual bug, sometimes hours later. Not fun to debug.

Pure managed code and single-call P/Invoke are fine, but those aren't why anyone passes pinned: true in the first place.

I think drop the two-arg overload and just polyfill AllocateUninitializedArray(int length)

@paulomorgado
Copy link
Copy Markdown
Contributor Author

Because I use it to allocate already pinned but always pin anyway, I never thought some could rely on that.

Maybe we should keep the parameter and throw on true.

@SimonCropp
Copy link
Copy Markdown
Owner

@paulomorgado yep, happy with that

…led with pinned=true

On older runtimes, pinned allocations cannot be performed, so the polyfill
now throws NotSupportedException instead of silently ignoring the parameter.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@paulomorgado paulomorgado force-pushed the gc-allocate-uninitialized-array branch from c7383ac to ddf9469 Compare April 15, 2026 09:02
@SimonCropp SimonCropp merged commit 1cb6523 into SimonCropp:main Apr 19, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants