From efaefb52f4bc7d27035c5a2091a16de8ed3e07dc Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Fri, 29 May 2026 12:37:35 +0200 Subject: [PATCH 1/3] Fix race between zlib Inflate/Deflate and Dispose Hold a SafeHandle ref via DangerousAddRef/Release around the native Inflate, InflateReset2_, and Deflate calls so a concurrent Dispose cannot run InflateEnd/DeflateEnd and free the zlib state from underneath an in-flight operation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/System/IO/Compression/ZLibNative.cs | 57 +++++++++++++++---- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/src/libraries/Common/src/System/IO/Compression/ZLibNative.cs b/src/libraries/Common/src/System/IO/Compression/ZLibNative.cs index 0a934dbd6e55cb..1cbe6cdc9c03f8 100644 --- a/src/libraries/Common/src/System/IO/Compression/ZLibNative.cs +++ b/src/libraries/Common/src/System/IO/Compression/ZLibNative.cs @@ -348,12 +348,23 @@ private unsafe void DeflateInit2_(CompressionLevel level, int windowBits, int me public unsafe ErrorCode Deflate(FlushCode flush) { - EnsureNotDisposed(); - EnsureState(State.InitializedForDeflate); + bool refAdded = false; + try + { + DangerousAddRef(ref refAdded); + EnsureState(State.InitializedForDeflate); - fixed (ZStream* stream = &_zStream) + fixed (ZStream* stream = &_zStream) + { + return Interop.ZLib.Deflate(stream, flush); + } + } + finally { - return Interop.ZLib.Deflate(stream, flush); + if (refAdded) + { + DangerousRelease(); + } } } @@ -395,23 +406,45 @@ private unsafe void InflateInit2_(int windowBits) public unsafe ErrorCode InflateReset2_(int windowBits) { - EnsureNotDisposed(); - EnsureState(State.InitializedForInflate); + bool refAdded = false; + try + { + DangerousAddRef(ref refAdded); + EnsureState(State.InitializedForInflate); - fixed (ZStream* stream = &_zStream) + fixed (ZStream* stream = &_zStream) + { + return Interop.ZLib.InflateReset2_(stream, windowBits); + } + } + finally { - return Interop.ZLib.InflateReset2_(stream, windowBits); + if (refAdded) + { + DangerousRelease(); + } } } public unsafe ErrorCode Inflate(FlushCode flush) { - EnsureNotDisposed(); - EnsureState(State.InitializedForInflate); + bool refAdded = false; + try + { + DangerousAddRef(ref refAdded); + EnsureState(State.InitializedForInflate); - fixed (ZStream* stream = &_zStream) + fixed (ZStream* stream = &_zStream) + { + return Interop.ZLib.Inflate(stream, flush); + } + } + finally { - return Interop.ZLib.Inflate(stream, flush); + if (refAdded) + { + DangerousRelease(); + } } } From a15ff168b19619531df0ed04cdca7cca5ddeaac6 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Fri, 29 May 2026 13:18:10 +0200 Subject: [PATCH 2/3] Remove unused EnsureNotDisposed helper Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Common/src/System/IO/Compression/ZLibNative.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/libraries/Common/src/System/IO/Compression/ZLibNative.cs b/src/libraries/Common/src/System/IO/Compression/ZLibNative.cs index 1cbe6cdc9c03f8..807c19fe37fd20 100644 --- a/src/libraries/Common/src/System/IO/Compression/ZLibNative.cs +++ b/src/libraries/Common/src/System/IO/Compression/ZLibNative.cs @@ -288,11 +288,6 @@ public uint AvailOut set { _zStream.availOut = value; } } - private void EnsureNotDisposed() - { - ObjectDisposedException.ThrowIf(InitializationState == State.Disposed, this); - } - private void EnsureState(State requiredState) { if (InitializationState != requiredState) @@ -370,7 +365,6 @@ public unsafe ErrorCode Deflate(FlushCode flush) public unsafe ErrorCode DeflateEnd() { - EnsureNotDisposed(); EnsureState(State.InitializedForDeflate); fixed (ZStream* stream = &_zStream) @@ -450,7 +444,6 @@ public unsafe ErrorCode Inflate(FlushCode flush) public unsafe ErrorCode InflateEnd() { - EnsureNotDisposed(); EnsureState(State.InitializedForInflate); fixed (ZStream* stream = &_zStream) From 74af2a0c49040393811737f9bbc956009829db04 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Mon, 1 Jun 2026 09:39:56 +0200 Subject: [PATCH 3/3] Make DeflateEnd/InflateEnd private --- src/libraries/Common/src/System/IO/Compression/ZLibNative.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/Common/src/System/IO/Compression/ZLibNative.cs b/src/libraries/Common/src/System/IO/Compression/ZLibNative.cs index 807c19fe37fd20..76de2405c2d388 100644 --- a/src/libraries/Common/src/System/IO/Compression/ZLibNative.cs +++ b/src/libraries/Common/src/System/IO/Compression/ZLibNative.cs @@ -363,7 +363,7 @@ public unsafe ErrorCode Deflate(FlushCode flush) } } - public unsafe ErrorCode DeflateEnd() + private unsafe ErrorCode DeflateEnd() { EnsureState(State.InitializedForDeflate); @@ -442,7 +442,7 @@ public unsafe ErrorCode Inflate(FlushCode flush) } } - public unsafe ErrorCode InflateEnd() + private unsafe ErrorCode InflateEnd() { EnsureState(State.InitializedForInflate);