Skip to content

[src] Fix GC-safety issues in a number of APIs.#26147

Merged
rolfbjarne merged 1 commit into
mainfrom
dev/rolf/handle-safety
Jul 17, 2026
Merged

[src] Fix GC-safety issues in a number of APIs.#26147
rolfbjarne merged 1 commit into
mainfrom
dev/rolf/handle-safety

Conversation

@rolfbjarne

Copy link
Copy Markdown
Member

Fix a batch of genuinely GC-unsafe hand-written binding methods flagged by the HandleSafety test: they fetched a native handle from a managed object but didn't keep that object alive across the native use of the handle, so the object could be collected (and finalized, invalidating the handle) while the native call was still in progress.

The fix is to keep the object alive until after the native call:

  • Most methods just add a GC.KeepAlive (obj) after the native call (capturing the return value in a local first where needed).
  • CoreFoundation.CFArray.Create captures the native return value in a local declared outside the 'fixed' block and calls GC.KeepAlive after it.
  • Darwin.SystemLog.Search is split so the native asl_search call runs in a normal method: in the original iterator the compiler hoists 'this' and 'msg' into the generated state machine, defeating the keep-alive analysis.

Methods fixed span AddressBook, AudioToolbox, AudioUnit, CoreFoundation, CoreGraphics, CoreMidi, CoreServices, CoreText, CoreVideo, Darwin, Foundation, ImageIO, NearbyInteraction, QuickLook, Security and VideoToolbox. The now-resolved entries are removed from tests/cecil-tests/HandleSafety.KnownFailures.cs.

Contributes towards #10146.

🤖 Pull request created by Copilot

…-written bindings.

Fix a batch of genuinely GC-unsafe hand-written binding methods flagged by the
HandleSafety test: they fetched a native handle from a managed object but didn't
keep that object alive across the native use of the handle, so the object could
be collected (and finalized, invalidating the handle) while the native call was
still in progress.

The fix is to keep the object alive until after the native call:
* Most methods just add a GC.KeepAlive (obj) after the native call (capturing
  the return value in a local first where needed).
* CoreFoundation.CFArray.Create captures the native return value in a local
  declared outside the 'fixed' block and calls GC.KeepAlive after it.
* Darwin.SystemLog.Search is split so the native asl_search call runs in a
  normal method: in the original iterator the compiler hoists 'this' and 'msg'
  into the generated state machine, defeating the keep-alive analysis.

Methods fixed span AddressBook, AudioToolbox, AudioUnit, CoreFoundation,
CoreGraphics, CoreMidi, CoreServices, CoreText, CoreVideo, Darwin, Foundation,
ImageIO, NearbyInteraction, QuickLook, Security and VideoToolbox. The now-
resolved entries are removed from tests/cecil-tests/HandleSafety.KnownFailures.cs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: dd86cf03-297a-43e8-ae1f-3c0b22bb67c4

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses GC-safety in multiple hand-written bindings by ensuring managed objects aren’t collected/finalized while their native handles are in use (typically by adding GC.KeepAlive after the P/Invoke/native call). This aligns with the HandleSafety test’s goal of preventing use-after-free of native handles derived from managed wrappers.

Changes:

  • Adds GC.KeepAlive patterns across a broad set of bindings that pass managed-derived native handles into native APIs.
  • Refactors Darwin.SystemLog.Search to avoid iterator state-machine hoisting interfering with keep-alive analysis.
  • Removes now-resolved entries from tests/cecil-tests/HandleSafety.KnownFailures.cs.

Reviewed changes

Copilot reviewed 30 out of 30 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tests/cecil-tests/HandleSafety.KnownFailures.cs Removes entries for APIs that are now GC-safe per HandleSafety expectations.
src/VideoToolbox/VTPixelTransferSession.cs Keeps the properties dictionary alive across VTSessionSetProperties.
src/VideoToolbox/VTPixelRotationSession.cs Keeps the properties dictionary alive across VTSessionSetProperties.
src/VideoToolbox/VTDecompressionSession.cs Keeps the properties dictionary alive across VTSessionSetProperties.
src/VideoToolbox/VTCompressionSession.cs Keeps the properties dictionary alive across VTSessionSetProperties.
src/Security/Items.cs Keeps keychain query dictionaries alive across SecItem* calls.
src/Security/Certificate.cs Keeps algorithm constants alive across SecKey* native calls.
src/QuickLook/Thumbnail.cs Keeps option keys alive across dictionary low-level set calls.
src/NearbyInteraction/NIAlgorithmConvergenceStatusReasonValues.cs Keeps the returned NSString constant alive across native description lookup.
src/ImageIO/CGImageSource.cs Keeps auxiliary-data type constant alive across native copy call.
src/ImageIO/CGImageDestination.cs Keeps auxiliary-data type constant alive across native add call.
src/Foundation/NSFastEnumerator.cs Keeps the enumerated collection alive across the objc_msgSend fast-enum call.
src/Foundation/NSDecimal.cs Keeps the current locale alive across NSDecimalString native call.
src/Darwin/SystemLog.cs Moves asl_search out of the iterator to ensure msg stays alive during the native call.
src/CoreVideo/CVPixelBufferPool.cs Keeps allocation settings alive across pixel buffer creation.
src/CoreVideo/CVPixelBuffer.cs Keeps pixel buffer attributes alive across native buffer creation calls.
src/CoreVideo/CVImageBuffer.cs Keeps strongly-typed string constants alive across code-point native lookups.
src/CoreText/CTTypesetter.cs Keeps options alive across native typesetter creation.
src/CoreText/CTTextTab.cs Keeps options alive across native text-tab creation.
src/CoreText/CTFramesetter.cs Keeps frame attributes alive across native frame-size suggestion call.
src/CoreText/CTFontCollection.cs Keeps options alive across native font-collection creation/matching calls.
src/CoreServices/FSEvents.cs Keeps allocator object alive across FSEventStreamCreate calls.
src/CoreMidi/MidiServices.cs Keeps MIDI objects alive across native add calls.
src/CoreGraphics/CGPDFDocument.cs Keeps outline options alive across native outline-setting call.
src/CoreFoundation/CFPreferences.cs Keeps key/application/value objects alive across CFPreferencesSetAppValue native calls.
src/CoreFoundation/CFDictionary.cs Keeps key/value arrays alive across CFDictionaryCreate.
src/CoreFoundation/CFArray.cs Keeps the values array alive across CFArrayCreate.
src/AudioUnit/AudioUnit.cs Keeps the preset dictionary alive across AudioUnitSetProperty.
src/AudioToolbox/MusicTrack.cs Keeps the owning sequence alive across MusicSequenceDisposeTrack.
src/AddressBook/ABMultiValue.cs Keeps the backing ABMultiValue alive across native calls for entry value/label/id access.
Comments suppressed due to low confidence (1)

src/Darwin/SystemLog.cs:256

  • aslresponse_free (search) is currently executed only if the iterator runs to completion. If the caller stops enumerating early (or the enumerator is disposed), the native aslresponse handle can leak because the cleanup code after the yield return loop will never run. Wrap the enumeration in a try/finally so the native response is freed even on early-exit, and guard against asl_search returning IntPtr.Zero.
		static IEnumerable<Message> EnumerateSearchResults (IntPtr search)
		{
			IntPtr mh;

			while ((mh = aslresponse_next (search)) != IntPtr.Zero)
				yield return new Message (mh, true);

			aslresponse_free (search);
		}

@vs-mobiletools-engineering-service2

This comment has been minimized.

@rolfbjarne
rolfbjarne marked this pull request as ready for review July 17, 2026 09:47
@rolfbjarne
rolfbjarne requested a review from dalexsoto as a code owner July 17, 2026 09:47
@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

✅ API diff for current PR / commit

NET (empty diffs)

✅ API diff vs stable

NET (empty diffs)

ℹ️ Generator diff

Generator Diff: vsdrops (html) vsdrops (raw diff) gist (raw diff) - Please review changes)

Pipeline on Agent
Hash: 2000d6379888a6c13374f77d458e25851bd5d1d9 [PR build]

@rolfbjarne
rolfbjarne enabled auto-merge (squash) July 17, 2026 11:18
@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

🚀 [CI Build #2000d63] Test results 🚀

Test results

✅ All tests passed on VSTS: test results.

🎉 All 203 tests passed 🎉

Tests counts

✅ assembly-processing: All 1 tests passed. Html Report (VSDrops) Download
✅ cecil: All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (iOS): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (MacCatalyst): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (macOS): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (Multiple platforms): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (tvOS): All 1 tests passed. Html Report (VSDrops) Download
✅ framework: All 2 tests passed. Html Report (VSDrops) Download
✅ fsharp: All 4 tests passed. Html Report (VSDrops) Download
✅ generator: All 5 tests passed. Html Report (VSDrops) Download
✅ interdependent-binding-projects: All 4 tests passed. Html Report (VSDrops) Download
✅ introspection: All 4 tests passed. Html Report (VSDrops) Download
✅ linker (iOS): All 15 tests passed. Html Report (VSDrops) Download
✅ linker (MacCatalyst): All 15 tests passed. [attempt 2] Html Report (VSDrops) Download
✅ linker (macOS): All 21 tests passed. Html Report (VSDrops) Download
✅ linker (tvOS): All 15 tests passed. Html Report (VSDrops) Download
✅ monotouch (iOS): All 19 tests passed. Html Report (VSDrops) Download
✅ monotouch (MacCatalyst): All 18 tests passed. Html Report (VSDrops) Download
✅ monotouch (macOS): All 19 tests passed. Html Report (VSDrops) Download
✅ monotouch (tvOS): All 19 tests passed. Html Report (VSDrops) Download
✅ msbuild: All 2 tests passed. Html Report (VSDrops) Download
✅ sharpie: All 1 tests passed. Html Report (VSDrops) Download
✅ windows: All 3 tests passed. Html Report (VSDrops) Download
✅ xcframework: All 4 tests passed. Html Report (VSDrops) Download
✅ xtro: All 1 tests passed. Html Report (VSDrops) Download

macOS tests

✅ Tests on macOS Monterey (12): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Ventura (13): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Sonoma (14): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Sequoia (15): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Tahoe (26): All 5 tests passed. Html Report (VSDrops) Download

Linux Build Verification

Linux build succeeded

Pipeline on Agent
Hash: 2000d6379888a6c13374f77d458e25851bd5d1d9 [PR build]

@rolfbjarne
rolfbjarne merged commit ef90b04 into main Jul 17, 2026
57 checks passed
@rolfbjarne
rolfbjarne deleted the dev/rolf/handle-safety branch July 17, 2026 16:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants