5

GZipStream を使用してデータを圧縮/解凍しています。ドキュメンテーションには、GZipStream が破損したデータを検出するための CRC も追加すると記載されているため、DeflateStream よりもこれを選択しました。これは、私が欲しかったもう 1 つの機能です。私の「肯定的な」単体テストは、一部のデータを圧縮し、圧縮されたバイト配列を保存してから、再び正常に解凍できるという点でうまく機能しています。.NET GZipStreamの圧縮と解凍に関する問題の投稿は、圧縮または解凍されたデータにアクセスする前に GZipStream を閉じる必要があることに気付きました。

次に、破損したデータを検出できることを確認するために、引き続き "ネガティブ" 単体テストを作成しました。以前、MSDN の GZipStream クラスの例を使用してファイルを圧縮し、圧縮ファイルをテキスト エディターで開き、1 バイトを変更してファイルを破損させました (テキスト エディターで開くだけでは不十分であるかのように!)。それを解凍して、期待どおりに InvalidDataException が発生したことを確認します。

単体テストを作成したとき、破損する任意のバイト (たとえば、compressedDataBytes[50] = 0x99) を選択し、InvalidDataException を取得しました。ここまでは順調ですね。気になったので、別のバイトを選んだのですが、驚いたことに、例外は発生しませんでした。データが正常に復元される限り、これは問題ない可能性があります (たとえば、データ ブロック内の未使用のバイトに偶然ヒットした場合など)。ただし、正しいデータも返されませんでした。

「私ではなかった」ことを確認するために、.NET GZipStream の圧縮と解凍の問題の下部からクリーンアップされたコードを取得し、適切に解凍できなくなるまで圧縮データの各バイトを順次破損するように修正しました。変更点は次のとおりです (Visual Studio 2010 テスト フレームワークを使用していることに注意してください)。

// successful compress / decompress example code from:
//    https://stackoverflow.com/questions/1590846/net-gzipstream-compress-and-decompress-problem
[TestMethod]
public void Test_zipping_with_memorystream_and_corrupting_compressed_data()
{
   const string sample = "This is a compression test of microsoft .net gzip compression method and decompression methods";
   var encoding = new ASCIIEncoding();
   var data = encoding.GetBytes(sample);
   string sampleOut = null;
   byte[] cmpData;

   // Compress 
   using (var cmpStream = new MemoryStream())
   {
      using (var hgs = new GZipStream(cmpStream, CompressionMode.Compress))
      {
         hgs.Write(data, 0, data.Length);
      }
      cmpData = cmpStream.ToArray();
   }

   int corruptBytesNotDetected = 0;

   // corrupt data byte by byte
   for (var byteToCorrupt = 0; byteToCorrupt < cmpData.Length; byteToCorrupt++)
   {
      // corrupt the data
      cmpData[byteToCorrupt]++;

      using (var decomStream = new MemoryStream(cmpData))
      {
         using (var hgs = new GZipStream(decomStream, CompressionMode.Decompress))
         {
            using (var reader = new StreamReader(hgs))
            {
               try
               {
                  sampleOut = reader.ReadToEnd();

                  // if we get here, the corrupt data was not detected by GZipStream
                  // ... okay so long as the correct data is extracted
                  corruptBytesNotDetected++;

                  var message = string.Format("ByteCorrupted = {0}, CorruptBytesNotDetected = {1}",
                     byteToCorrupt, corruptBytesNotDetected);

                  Assert.IsNotNull(sampleOut, message);
                  Assert.AreEqual(sample, sampleOut, message);
               }
               catch(InvalidDataException)
               {
                  // data was corrupted, so we expect to get here
               }
            }
         }
      }

      // restore the data
      cmpData[byteToCorrupt]--;
   }
}

このテストを実行すると、次のようになります。

Assert.AreEqual failed. Expected:<This is a compression test of microsoft .net gzip compression method and decompression methods>. Actual:<>. ByteCorrupted = 11, CorruptBytesNotDetected = 8

したがって、これは実際には、データを破損しても違いがなかった (文字列が正常に復元された) 7 つのケースがあったことを意味しますが、バイト 11 を破損しても例外はスローされず、データも復元されませんでした。

私は何かを見逃していますか、何か間違っていますか? 破損した圧縮データが検出されない理由を誰でも確認できますか?

4

1 に答える 1

7

gzip 形式の 10 バイトのヘッダーがあり、最後の 7 バイトを変更しても解凍エラーが発生しません。したがって、破損のない、指摘した 7 つのケースが期待されます。

ストリーム内の他の場所で破損を伴うエラーが検出されないことはほとんどありません。ほとんどの場合、デコンプレッサは圧縮されたデータのフォーマットにエラーを検出し、crc をチェックするまでには至りません。それがcrcをチェックする段階に達した場合、そのチェックは入力ストリームが破損しているため、ほぼ常に失敗するはずです。(「ほぼ常に」とは、約 1 - 2^-32 の確率を意味します。)

84バイトのgzipストリームを生成するサンプル文字列を使用して(zlibを使用したCで)試しました。84 バイトのそれぞれをインクリメントして残りを同じままにすると、次の結果になりました: 2 つのヘッダー チェックの誤り、1 つの無効な圧縮方法、7 つの成功、1 つの無効なブロック タイプ、4 つの無効な距離の設定、7 つの無効なコード長の設定、4 つの欠落ブロックの終わり、11 の無効なビット長の繰り返し、3 つの無効なビット長の繰り返し、2 つの無効なビット長の繰り返し、2 つの予期しないストリームの終わり、36 の不正なデータ チェック (実際の CRC エラー)、および 4 つの不正な長さのチェック (別のチェック)正しい非圧縮データ長の gzip 形式)。破損した圧縮ストリームが検出されなかったケースはありません。

したがって、コードまたはクラスのどこかにバグがあるはずです。

アップデート:

クラスにバグがあるようです。

驚くべきことに (またはそうではないかもしれませんが)、Microsoft はこのバグを修正しないと結論付けました!

于 2012-02-27T05:17:35.037 に答える