这是Java GZipInputStream类中的一个bug吗?

11
我注意到我的gzip解码代码似乎无法检测到损坏的数据。我认为我已经找到了问题所在,是由于Java GZipInputStream类。特别是,当你用一个单独的“read”调用读取整个流时,损坏的数据不会触发IOException。如果你在同一段损坏的数据上进行2次或更多次的读取,则会触发异常。
在考虑提交错误报告之前,我想知道这里的社区对此有何看法。
编辑:我修改了我的示例,因为上一个示例没有清楚地说明我认为的问题。在这个新的示例中,一个10字节的缓冲区被压缩,修改了一个字节的压缩缓冲区,然后被解压缩。调用“GZipInputStream.read”返回读取的字节数为10,这是一个10字节缓冲区的预期值。然而,未压缩的缓冲区与原始缓冲区不同(由于损坏)。没有抛出异常。我注意到,在读取后调用“available”返回“1”,而不是达到EOF时应该返回的“0”。
以下是源代码:
  @Test public void gzip() {
    try {
      int length = 10;
      byte[] bytes = new byte[]{12, 19, 111, 14, -76, 34, 60, -43, -91, 101};
      System.out.println(Arrays.toString(bytes));

      //Gzip the byte array
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      GZIPOutputStream gos = new GZIPOutputStream(baos);
      gos.write(bytes);
      gos.finish();
      byte[] zipped = baos.toByteArray();

      //Alter one byte of the gzipped array.  
      //This should be detected by gzip crc-32 checksum
      zipped[15] = (byte)(0);

      //Unzip the modified array
      ByteArrayInputStream bais = new ByteArrayInputStream(zipped);
      GZIPInputStream gis = new GZIPInputStream(bais);
      byte[] unzipped = new byte[length];
      int numRead = gis.read(unzipped);
      System.out.println("NumRead: " + numRead);
      System.out.println("Available: " + gis.available());

      //The unzipped array is now [12, 19, 111, 14, -80, 0, 0, 0, 10, -118].
      //No IOException was thrown.
      System.out.println(Arrays.toString(unzipped));

      //Assert that the input and unzipped arrays are equal (they aren't)
      org.junit.Assert.assertArrayEquals(unzipped, bytes);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

1
+1 好问题;写得很好,包含自足、简洁、可运行的示例。这就是为什么你得到了如此快速的答案 :-) - Jim Garrison
1个回答

9

决定运行测试:

你可能遗漏了什么。 gis.read(unzipped) 返回1,所以它只读取了一个字节。你不能抱怨,这并不是流的结尾。

下一步的read() 抛出了“损坏的GZIP尾部”错误。

所以一切都很好! (至少在GZIPInputStream中没有bug)


+1 你比我先发了 :-) 至少我在 JDK 中玩得很开心 :-) - Jim Garrison
实际上,当我看到这段代码时,我有超过99%的把握知道会发生什么。byte[]{0,0,-1,-1}是Z_SYNC_FLUSH的标记,所以我认为他可能已经触发了它。 - bestsss
我从未使用过GZIPInputStream,因此我必须对其进行跟踪。我认为关键在于损坏出现在尾部而不是数据中? - Jim Garrison
2
该方法会阻塞,直到有输入数据可用,因此如果存在一些数据,则该方法不需要返回所有数据。在我看来这是可以接受的:请参阅gzip本身的文档:该方法将阻塞,直到某些输入可以被解压缩 - bestsss
我将我的示例更改为一个示例,其中“read”返回与预期相同的字节数。 - Jacob
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接