-
Bug
-
Resolution: Fixed
-
P1
-
9
-
b179
-
windows
-
Verified
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8185421 | 10 | Xueming Shen | P1 | Resolved | Fixed | b18 |
JDK-8189035 | 9.0.6 | Xueming Shen | P1 | Resolved | Fixed | team |
JDK-8188299 | 9.0.4 | Xueming Shen | P1 | Resolved | Fixed | b01 |
JDK-8185524 | 9.0.1 | Xueming Shen | P1 | Closed | Fixed | b04 |
It appears the j.u.Deflater compression functionality is broken when
(1) level/strategy is changed (to new value) + (2) reset,()
which is a normal combination/use scenario when the deflater is being cached and reused. The attached test case fails with 1.2.11 (with data size > the DeflaterOutputStream's internal buffer size).
My reading of the 1.2.11 changes suggests the direct trigger is that the internal state "deflate_state.high_water" is not being reset correctly/appropriately in deflateReset/deflateResetKeep/lm_init().
It triggers a regression from 1.2.8 to 1.2.11 in the scenario that the "strategy/levle is changed" AND a followup "reset" is called (withe the assumption that everything should be reset back to initial state and we start a new compression circle, with the new level and strategy. This is how it worked in 1.2.8). Because one of the condition check is changed from "strm->total_in!=0" to "s->high_water" (for the flush last buffer" branch) in deflate.c/deflateParams().
from (1.2.8's)
if ((strategy != s->strategy || func != configuration_table[level].func) &&
strm->total_in != 0) {
/* Flush the last buffer: */
err = deflate(strm, Z_BLOCK);
if (err == Z_BUF_ERROR && s->pending == 0)
err = Z_OK;
}
to (1.2.11's)
if ((strategy != s->strategy || func != configuration_table[level].func) &&
s->high_water) {
/* Flush the last buffer: */
int err = deflate(strm, Z_BLOCK);
if (err == Z_STREAM_ERROR)
return err;
if (strm->avail_out == 0)
return Z_BUF_ERROR;
}
Given the nature of "reset" it seems reasonable to assume the "high_water" should be reset to 0, its initial value as well, inside either deflateResetKeep() or lm_init().
I have logged an issue at
https://github.com/madler/zlib/issues/275
Given jdk9 has been changed to uses the system zlib for all platforms except the windows, this one currently only fails on windows (but I would assume it will fails if the underlying system zlib is 1.2.11)
-------------------------------- test case ----------------------------------------------------
public static void main(final String[] args) throws IOException {
Path p = Paths.get("jms.compression.data.large");
int[] levels = new int[] {
Deflater.DEFAULT_COMPRESSION,
0,
Deflater.BEST_SPEED,
// 2, 3, 4, 5, 6, 7, 8,
Deflater.BEST_COMPRESSION,
};
try {
byte[] src = Files.readAllBytes(p);
if (src.length == 0) return;
Deflater def = new Deflater(Deflater.DEFAULT_COMPRESSION); //, true);
for (int level : levels) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
System.out.println(" -------------- level:" + level + " ------------------");
def.setLevel(level);
def.reset();
try (DeflaterOutputStream defos = new DeflaterOutputStream(baos, def)) {
defos.write(src);
}
byte[] compressed = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(compressed);
Inflater inf = new Inflater();
try (InflaterInputStream infis = new InflaterInputStream(bais, inf)) {
byte[] bytes = infis.readAllBytes();
if (!Arrays.equals(src, bytes)) {
System.out.println(" ==> NG");
new Exception().printStackTrace();
} else {
System.out.println(" ==> OK");
}
} catch (Exception x) {
System.out.println(" ==> NG");
x.printStackTrace();
}
}
} catch (IOException x) {
x.printStackTrace();
}
}
(1) level/strategy is changed (to new value) + (2) reset,()
which is a normal combination/use scenario when the deflater is being cached and reused. The attached test case fails with 1.2.11 (with data size > the DeflaterOutputStream's internal buffer size).
My reading of the 1.2.11 changes suggests the direct trigger is that the internal state "deflate_state.high_water" is not being reset correctly/appropriately in deflateReset/deflateResetKeep/lm_init().
It triggers a regression from 1.2.8 to 1.2.11 in the scenario that the "strategy/levle is changed" AND a followup "reset" is called (withe the assumption that everything should be reset back to initial state and we start a new compression circle, with the new level and strategy. This is how it worked in 1.2.8). Because one of the condition check is changed from "strm->total_in!=0" to "s->high_water" (for the flush last buffer" branch) in deflate.c/deflateParams().
from (1.2.8's)
if ((strategy != s->strategy || func != configuration_table[level].func) &&
strm->total_in != 0) {
/* Flush the last buffer: */
err = deflate(strm, Z_BLOCK);
if (err == Z_BUF_ERROR && s->pending == 0)
err = Z_OK;
}
to (1.2.11's)
if ((strategy != s->strategy || func != configuration_table[level].func) &&
s->high_water) {
/* Flush the last buffer: */
int err = deflate(strm, Z_BLOCK);
if (err == Z_STREAM_ERROR)
return err;
if (strm->avail_out == 0)
return Z_BUF_ERROR;
}
Given the nature of "reset" it seems reasonable to assume the "high_water" should be reset to 0, its initial value as well, inside either deflateResetKeep() or lm_init().
I have logged an issue at
https://github.com/madler/zlib/issues/275
Given jdk9 has been changed to uses the system zlib for all platforms except the windows, this one currently only fails on windows (but I would assume it will fails if the underlying system zlib is 1.2.11)
-------------------------------- test case ----------------------------------------------------
public static void main(final String[] args) throws IOException {
Path p = Paths.get("jms.compression.data.large");
int[] levels = new int[] {
Deflater.DEFAULT_COMPRESSION,
0,
Deflater.BEST_SPEED,
// 2, 3, 4, 5, 6, 7, 8,
Deflater.BEST_COMPRESSION,
};
try {
byte[] src = Files.readAllBytes(p);
if (src.length == 0) return;
Deflater def = new Deflater(Deflater.DEFAULT_COMPRESSION); //, true);
for (int level : levels) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
System.out.println(" -------------- level:" + level + " ------------------");
def.setLevel(level);
def.reset();
try (DeflaterOutputStream defos = new DeflaterOutputStream(baos, def)) {
defos.write(src);
}
byte[] compressed = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(compressed);
Inflater inf = new Inflater();
try (InflaterInputStream infis = new InflaterInputStream(bais, inf)) {
byte[] bytes = infis.readAllBytes();
if (!Arrays.equals(src, bytes)) {
System.out.println(" ==> NG");
new Exception().printStackTrace();
} else {
System.out.println(" ==> OK");
}
} catch (Exception x) {
System.out.println(" ==> NG");
x.printStackTrace();
}
}
} catch (IOException x) {
x.printStackTrace();
}
}
- backported by
-
JDK-8185421 zlib 1.2.11 upgrade triggers j.u.zip.Deflater regression
-
- Resolved
-
-
JDK-8188299 zlib 1.2.11 upgrade triggers j.u.zip.Deflater regression
-
- Resolved
-
-
JDK-8189035 zlib 1.2.11 upgrade triggers j.u.zip.Deflater regression
-
- Resolved
-
-
JDK-8185524 zlib 1.2.11 upgrade triggers j.u.zip.Deflater regression
-
- Closed
-
- relates to
-
JDK-8185101 java/util/zip/DeInflate.java fails at Ubuntu 17.04 (zlib 1.2.11)
-
- Closed
-
-
JDK-8173140 To upgrade bundled zlib version from 1.2.8 to 1.2.11
-
- Closed
-
- links to
(1 relates to, 1 links to)