GZipStream fails to write to MemoryStream in .NET 4.5 - by Gareth Oakley

Status : 

  Won't Fix<br /><br />
		Due to several factors the product team decided to focus its efforts on other items.<br /><br />
		A more detailed explanation for the resolution of this particular item may have been provided in the comments section.


12
0
Sign in
to vote
ID 742481 Comments
Status Closed Workarounds
Type Bug Repros 7
Opened 5/17/2012 4:11:17 AM
Access Restriction Public
Moderator Decision Sent to Engineering Team for consideration

Description

GZipStream no longer writes to MemoryStream objects correctly in .NET 4.5. This functionality works correctly in previous versions of the .NET framework.

It appears that as of .NET 4.5 you must call Dispose on GZipStream before it writes data - previous versions appeared to flush automatically.
Sign in to post a comment.
Posted by Alexandru [MSFT] on 10/21/2014 at 9:54 AM
Hi Gareth

The issue you are seeing was caused by the fact that we changed the underlying compression library. The workround presented in the link below is going to work.

We are not going to be able to address this issue in our next release due to other priorities.

Thanks you.
Posted by Peter Kuhn on 9/12/2013 at 8:20 AM
This is also relevant for the newly released Microsoft.Bcl.Compression library and in my opinion a quite unexpected behavior.

Details: http://www.pitorque.de/MisterGoodcat/post/Working-around-a-bug-in-MicrosoftBclCompression.aspx
Posted by DotNetWise on 4/6/2013 at 1:18 PM
This is still a bug in .NET 4.5 RTM.
Even if you look at documentation you can see the difference between .NET 4.5 and previous versions of .NET

So this is really a breaking change!!!
Posted by Hantrenar on 1/14/2013 at 10:43 AM
This is a behavior change from 4.0 to 4.5. The code below works fine in 4.0:
            using (MemoryStream ms = new MemoryStream())
            using (GZipStream gzs = new GZipStream(ms, CompressionMode.Compress))
            {
                byte[] bytes = Encoding.UTF8.GetBytes(toCompress);
                gzs.Write(bytes, 0, bytes.Length);
                returnValue = Convert.ToBase64String(ms.ToArray());
            }

When running this code against 4.5 the stream never gets written and returnValue is an empty string (base64 encoded in this case). This seems like a pretty bad regression to me in that 4.5 will break existing 4.0 code, and do so silently.

Throwing in the line below before setting returnValue works around the issue, but it's kind of a hack
                // Testing fix for .net framework bug. Safe to call dispose twice
                gzs.Dispose();

Again, this code is perfectly valid, and worked fine in 4.0.
Posted by Microsoft on 5/21/2012 at 8:23 PM
Hi Gareth !

Thanks for bringing up this interesting issue. We are always grateful when customers point towards potential concerns - this helps us ensuring the quality of the .NET Framework and driving the product into the right direction.

You analysis hints at an issue related to GZipStream and DeflateStream, however, the issue is slightly different from what you are hinting at.
Add the following code at the end of your repro:

    Console.WriteLine("Verifying..");

    memoryStream.Seek(0, SeekOrigin.Begin);
    GZipStream unpackStream = new GZipStream(memoryStream, CompressionMode.Decompress);
    StreamReader reader = new StreamReader(unpackStream);

    String line = reader.ReadLine();
    while (line != null) {
        Console.WriteLine(line);
        line = reader.ReadLine();
    }

You will see that the behaviour is *identical* in .NET 4.0 and in .NET 4.5 Beta. Nothing gets printed.
In fact, we have improved our compression engine. As you have correctly observed, this “nothing” used to take up 122 bytes in .NET 4.0 and it takes only 10 bytes in .NET 4.5 Beta. These bytes are used for headers.

Indeed, the Flush method on GZipStream (and on DeflateStream) is a no-op. As you already observed, you can add the following statement right after the WriteLine statement and you will see that the test output will be printed. However, this works exactly the same in .NET 4.0 and in .NET 4.5 Beta:

    Console.WriteLine("Verifying..");
    gzipStream.Dispose();

Arguably, this is not what users may expect, but we cannot change this at present because it may affect the behaviour of existing programs. Modifying an API to behave differently in this way can cause existing applications to fail. If someone runs an application that does not expect the behaviour at the particular code location, it may be that that application suddenly fails on systems that apply our update/fix.

Although we cannot change the current system behaviour for compatibility reasons as described, we have logged it and will continue thinking about fixing this bug without violating our compatibility constraints. I will also contact our doc team to make sure this issue is noted correctly on MSDN.

I hope this helps.

Greg
(Software Engineer on the .NET Base Class Libraries team)
Posted by MS-Moderator07 [Feedback Moderator] on 5/17/2012 at 9:47 PM
Thanks for your feedback.

We are rerouting this issue to the appropriate group within the Visual Studio Product Team for triage and resolution. These specialized experts will follow-up with your issue.

Posted by MS-Moderator01 on 5/17/2012 at 4:43 AM
Thank you for your feedback, we are currently reviewing the issue you have submitted. If this issue is urgent, please contact support directly(http://support.microsoft.com)