From b5326e6d75d3e471a86ca0f9fc64dde1048241c2 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Tue, 28 Mar 2023 01:49:27 +0200 Subject: [PATCH] fix encodedAlphaData leak and #2171 --- .../Formats/Webp/Lossy/Vp8Encoder.cs | 100 ++++++++++-------- 1 file changed, 54 insertions(+), 46 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs index 695359e5ea..37cb9a4fc4 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs @@ -329,60 +329,68 @@ public void Encode(Image image, Stream stream) bool alphaCompressionSucceeded = false; using var alphaEncoder = new AlphaEncoder(); Span alphaData = Span.Empty; - if (hasAlpha) + IMemoryOwner encodedAlphaData = null; + try { - // TODO: This can potentially run in an separate task. - IMemoryOwner encodedAlphaData = alphaEncoder.EncodeAlpha(image, this.configuration, this.memoryAllocator, this.alphaCompression, out alphaDataSize); - alphaData = encodedAlphaData.GetSpan(); - if (alphaDataSize < pixelCount) + if (hasAlpha) { - // Only use compressed data, if the compressed data is actually smaller then the uncompressed data. - alphaCompressionSucceeded = true; + // TODO: This can potentially run in an separate task. + encodedAlphaData = alphaEncoder.EncodeAlpha(image, this.configuration, this.memoryAllocator, this.alphaCompression, out alphaDataSize); + alphaData = encodedAlphaData.GetSpan(); + if (alphaDataSize < pixelCount) + { + // Only use compressed data, if the compressed data is actually smaller then the uncompressed data. + alphaCompressionSucceeded = true; + } } - } - // Stats-collection loop. - this.StatLoop(width, height, yStride, uvStride); - it.Init(); - it.InitFilter(); - var info = new Vp8ModeScore(); - var residual = new Vp8Residual(); - do - { - bool dontUseSkip = !this.Proba.UseSkipProba; - info.Clear(); - it.Import(y, u, v, yStride, uvStride, width, height, false); - - // Warning! order is important: first call VP8Decimate() and - // *then* decide how to code the skip decision if there's one. - if (!this.Decimate(it, ref info, this.rdOptLevel) || dontUseSkip) - { - this.CodeResiduals(it, info, residual); - } - else + // Stats-collection loop. + this.StatLoop(width, height, yStride, uvStride); + it.Init(); + it.InitFilter(); + var info = new Vp8ModeScore(); + var residual = new Vp8Residual(); + do { - it.ResetAfterSkip(); + bool dontUseSkip = !this.Proba.UseSkipProba; + info.Clear(); + it.Import(y, u, v, yStride, uvStride, width, height, false); + + // Warning! order is important: first call VP8Decimate() and + // *then* decide how to code the skip decision if there's one. + if (!this.Decimate(it, ref info, this.rdOptLevel) || dontUseSkip) + { + this.CodeResiduals(it, info, residual); + } + else + { + it.ResetAfterSkip(); + } + + it.SaveBoundary(); } + while (it.Next()); - it.SaveBoundary(); + // Store filter stats. + this.AdjustFilterStrength(); + + // Write bytes from the bitwriter buffer to the stream. + ImageMetadata metadata = image.Metadata; + metadata.SyncProfiles(); + this.bitWriter.WriteEncodedImageToStream( + stream, + metadata.ExifProfile, + metadata.XmpProfile, + (uint)width, + (uint)height, + hasAlpha, + alphaData.Slice(0, alphaDataSize), + this.alphaCompression && alphaCompressionSucceeded); + } + finally + { + encodedAlphaData?.Dispose(); } - while (it.Next()); - - // Store filter stats. - this.AdjustFilterStrength(); - - // Write bytes from the bitwriter buffer to the stream. - ImageMetadata metadata = image.Metadata; - metadata.SyncProfiles(); - this.bitWriter.WriteEncodedImageToStream( - stream, - metadata.ExifProfile, - metadata.XmpProfile, - (uint)width, - (uint)height, - hasAlpha, - alphaData, - this.alphaCompression && alphaCompressionSucceeded); } ///