Potential AccessViolation at process exit on .NET Framework - SafeHandle finalizers now race `git_libgit2_shutdown`
Dieses Issue hat noch niemand übernommen.
Bewertung
- Schwierigkeit
- 4/5
- Geschätzter Aufwand
- 3-5 Tage
- Anfängerfreundlichkeit
- 52/100
Rechercherichtung
Verfolge NativeShutdownObject, Libgit2Object und NativeMethods.git_libgit2_init, um die Reihenfolge von Shutdown und SafeHandle-Finalisierung zu verstehen. Reproduziere das net472 server-GC-Szenario mit einem nicht freigegebenen Repository und beobachte das Beenden des Prozesses. Erledigt ist dies, wenn der Prozess ohne eine AccessViolation beendet wird und der native Shutdown sowie die Bereinigung der Handles nicht miteinander konkurrieren können.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
Disclaimer: the below is AI-assisted but I'm reasonably confident it all checks out.
Starting with 0.31 (specifically #2127 - Use Safe Handles), a Repository that is still alive when a .NET Framework process exits crashes the process with an AccessViolation inside git_repository_free / git_odb_free:
ntdll!RtlpWaitOnCriticalSection+0xa6 <- DebugInfo == NULL: critical section already deleted
ntdll!RtlEnterCriticalSection+0x42
git2!<mwindow.c static> <- git_mwindow_put_pack / packfile free, global mwindow mutex
git2!<odb_pack.c static> <- pack backend free
git2!git_odb_free+0x7a
git2!git_repository__cleanup / git_repository_free
LibGit2Sharp.Core.Handles.RepositoryHandle.ReleaseHandle() (or ObjectDatabaseHandle.ReleaseHandle)
System.Runtime.InteropServices.SafeHandle.Finalize()
clr!FinalizerThread::FinalizeAllObjects <- main thread is in clr!EEShutDown
git_libgit2_shutdown has already run from NativeShutdownObject's finalizer and destroyed libgit2's global mutexes.
Root cause
NativeShutdownObject derives from CriticalFinalizerObject on purpose: commit 247ca1a3 (2012, "Make git_threads_shutdown run after git finalizers") fixed this very crash by relying on the CLR guarantee that all normal finalizers run before any critical finalizer, so shutdown was always last.
#2127 made Libgit2Object derive from SafeHandleZeroOrMinusOneIsInvalid. SafeHandle is itself a CriticalFinalizerObject, so every handle finalizer now runs in the same critical phase as the shutdown object, and the relative order is undefined (with server GC it depends on which heap each object was allocated on, so it is intermittent).
Repro (net472, server GC)
App.config with <gcServer enabled="true"/>; open a repository on ~24 threads, read a few commits on each, keep the Repository objects alive in a static, return from Main without disposing. Crashes 10/10 on 0.32.0. With one extra git_libgit2_init() call (so the shutdown finalizer never reaches count 0) it passes 10/10.
Suggested fix
Never tear the native library down from a finalizer at all. The finalizer-based shutdown only ever executes on .NET Framework (Core does not run finalizers at process exit), and there it is now actively harmful because SafeHandles are guaranteed to be finalized in the same phase. Options:
- Delete
NativeShutdownObject; leave the process-lifetimegit_libgit2_initreference outstanding (the OS reclaims everything at exit). - Or keep it but make its finalizer a no-op when
AppDomain.CurrentDomain.IsFinalizingForUnload() || Environment.HasShutdownStarted.
Workaround for consumers today: call the internal NativeMethods.git_libgit2_init once more via reflection so the refcount never drops to zero.
- Vorherrschende Sprache
- C#
- Sterne
- 3.5k
- Forks
- 925
- PR-Merge-Kennzahlen
- Keine gemergten PRs in 30 T.
Beitragsleitfaden
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus libgit2/libgit2sharp
-
Schwierigkeit 4/5 3-5 Tage Anfängerfreundlichkeit 38/100
libgit2/libgit2sharp#2192 · 1 Kommentar ·
-
Website is down Offen
Schwierigkeit 4/5 3-5 Tage Anfängerfreundlichkeit 20/100
libgit2/libgit2sharp#2191 · 2 Reaktionen ·
-
Schwierigkeit 3/5 1-2 Tage Anfängerfreundlichkeit 68/100
libgit2/libgit2sharp#2189 · 1 Reaktion ·
-
Schwierigkeit 3/5 1-2 Tage Anfängerfreundlichkeit 35/100
libgit2/libgit2sharp#2187 · 2 Kommentare ·
-
Schwierigkeit 3/5 1-2 Tage Anfängerfreundlichkeit 48/100
libgit2/libgit2sharp#2184 · 1 Kommentar ·
Alle Issues in libgit2/libgit2sharp
Ähnliche Issues
-
bug
Schwierigkeit 1/5 Unter einer Stunde Anfängerfreundlichkeit 75/100
sillsdev/languageforge-lexbox#2665 ·
-
bug documentation frontend
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 72/100
azurenoops/spin_agent#975 ·
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 86/100
-
:watch: Not Triaged 11.0 fundamentals/subsvc
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 92/100
dotnet/AspNetCore.Docs#37699 ·
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 72/100
SubtitleEdit/subtitleedit#15108 · 1 Kommentar ·