From cb94cd9a8b69176b365d5f821b5d69c1e73deed5 Mon Sep 17 00:00:00 2001 From: Oski Kervinen Date: Fri, 19 Jul 2024 11:28:20 +0300 Subject: [PATCH 1/2] Fixed: SymWriter COM object is not released on exception The Problem: Problem observed when being used in coverlet: https://github.com/coverlet-coverage/coverlet/issues/1471 If an exception caused `NativePdbWriter.Write` to never be called, it would not call `SymWriter.Close`, which in turn meant `Marshal.ReleaseComObject` was left uncalled. The garbage collector will eventually destroy the object and thereby release the COM object, but that happens non-deterministically. The COM object is holding to a file handle, which prevents other operations on the written file until it is released. The result was random file access issues. The Solution: Luckily NativePdbWriter is IDisposable. I added a call to `writer.Close` there. But now it could be called twice, so I had to add a boolean to SymWriter to avoid releasing everything twice. --- symbols/pdb/Mono.Cecil.Pdb/NativePdbWriter.cs | 1 + symbols/pdb/Mono.Cecil.Pdb/SymWriter.cs | 12 ++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/symbols/pdb/Mono.Cecil.Pdb/NativePdbWriter.cs b/symbols/pdb/Mono.Cecil.Pdb/NativePdbWriter.cs index 7bb9c6f15..9597d7fa4 100644 --- a/symbols/pdb/Mono.Cecil.Pdb/NativePdbWriter.cs +++ b/symbols/pdb/Mono.Cecil.Pdb/NativePdbWriter.cs @@ -267,6 +267,7 @@ public void Write () public void Dispose () { + writer.Close (); } } diff --git a/symbols/pdb/Mono.Cecil.Pdb/SymWriter.cs b/symbols/pdb/Mono.Cecil.Pdb/SymWriter.cs index f309f2f6c..68bbfa90d 100644 --- a/symbols/pdb/Mono.Cecil.Pdb/SymWriter.cs +++ b/symbols/pdb/Mono.Cecil.Pdb/SymWriter.cs @@ -30,6 +30,7 @@ static extern int CoCreateInstance ( readonly ISymUnmanagedWriter2 writer; readonly Collection documents; + bool closed = false; public SymWriter () { @@ -78,11 +79,14 @@ public void DefineConstant2 (string name, object value, int sigToken) public void Close () { - writer.Close (); - Marshal.ReleaseComObject (writer); + if( !closed ) { + closed = true; + writer.Close (); + Marshal.ReleaseComObject ( writer ); - foreach (var document in documents) - Marshal.ReleaseComObject (document); + foreach( var document in documents ) + Marshal.ReleaseComObject ( document ); + } } public void CloseMethod () From 663532b207a4511a33b88427151bb634308531f9 Mon Sep 17 00:00:00 2001 From: Jb Evain Date: Wed, 25 Sep 2024 07:56:21 -0700 Subject: [PATCH 2/2] Code style --- symbols/pdb/Mono.Cecil.Pdb/SymWriter.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/symbols/pdb/Mono.Cecil.Pdb/SymWriter.cs b/symbols/pdb/Mono.Cecil.Pdb/SymWriter.cs index 68bbfa90d..fcc92611c 100644 --- a/symbols/pdb/Mono.Cecil.Pdb/SymWriter.cs +++ b/symbols/pdb/Mono.Cecil.Pdb/SymWriter.cs @@ -79,14 +79,15 @@ public void DefineConstant2 (string name, object value, int sigToken) public void Close () { - if( !closed ) { - closed = true; - writer.Close (); - Marshal.ReleaseComObject ( writer ); + if (closed) + return; - foreach( var document in documents ) - Marshal.ReleaseComObject ( document ); - } + closed = true; + writer.Close (); + Marshal.ReleaseComObject (writer); + + foreach (var document in documents) + Marshal.ReleaseComObject (document); } public void CloseMethod ()