From b8a9deab9a60a3aabc1b4fca2e829526ac486d02 Mon Sep 17 00:00:00 2001 From: wangzq Date: Mon, 12 Mar 2018 09:26:31 -0700 Subject: [PATCH] Fix crashing bug in finalizer Reproducing code: private async void button1_Click(object sender, EventArgs e) { button1.Enabled = false; var file = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "small.cab"); var tasks = Enumerable.Range(0, 1000).Select(_ => { return Task.Run(() => TestCab(file)); }); await Task.WhenAll(tasks); button1.Enabled = true; } --- src/DTF/Libraries/Compression.Cab/CabPacker.cs | 10 ++++------ src/DTF/Libraries/Compression.Cab/CabUnpacker.cs | 14 ++++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/DTF/Libraries/Compression.Cab/CabPacker.cs b/src/DTF/Libraries/Compression.Cab/CabPacker.cs index f263ae2be..7e473f787 100644 --- a/src/DTF/Libraries/Compression.Cab/CabPacker.cs +++ b/src/DTF/Libraries/Compression.Cab/CabPacker.cs @@ -424,13 +424,11 @@ protected override void Dispose(bool disposing) { try { - if (disposing) + // See comment in CabUnpacker.Dispose for more info. + if (this.fciHandle != null) { - if (this.fciHandle != null) - { - this.fciHandle.Dispose(); - this.fciHandle = null; - } + this.fciHandle.Dispose(); + this.fciHandle = null; } } finally diff --git a/src/DTF/Libraries/Compression.Cab/CabUnpacker.cs b/src/DTF/Libraries/Compression.Cab/CabUnpacker.cs index 32b33a0c2..9989efd8c 100644 --- a/src/DTF/Libraries/Compression.Cab/CabUnpacker.cs +++ b/src/DTF/Libraries/Compression.Cab/CabUnpacker.cs @@ -324,13 +324,15 @@ protected override void Dispose(bool disposing) { try { - if (disposing) + // While fdiHandle is a SafeHandle, it will callback to C# method from this instance + // when releasing handle, and since finalizers execute in nondeterministic order, if + // the handle's finalizer runs after this instance, it will get exception and crash + // the process. Therefore we must release this handle regardless of the 'disposing' + // flag. + if (this.fdiHandle != null) { - if (this.fdiHandle != null) - { - this.fdiHandle.Dispose(); - this.fdiHandle = null; - } + this.fdiHandle.Dispose(); + this.fdiHandle = null; } } finally