Subject: [Bug 3603553]: Ensure that data gets written to the underlying stream by compressing transforms when the amount of data to be written is one buffer's-worth; problem was particularly likely to occur when compressing large quantities of not-very-compressible data.

From: dkf <[email-masked]>
Date: Mon, 11 Feb 2013 08:11:28 +0000

Many thanks to Piera Poggio (vampiera) for reporting.
---
 ChangeLog         |  9 +++++++++
 generic/tclZlib.c |  2 +-
 tests/zlib.test   | 19 +++++++++++++++++++
 3 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog
index 743c571..64d80c1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2013-02-11  Donal K. Fellows  <[email-masked]>
+
+	* generic/tclZlib.c (ZlibTransformOutput): [Bug 3603553]: Ensure that
+	data gets written to the underlying stream by compressing transforms
+	when the amount of data to be written is one buffer's-worth; problem
+	was particularly likely to occur when compressing large quantities of
+	not-very-compressible data. Many thanks to Piera Poggio (vampiera) for
+	reporting.
+
 2013-02-09  Donal K. Fellows  <[email-masked]>
 
 	* generic/tclOOBasic.c (TclOO_Object_VarName): [Bug 3603695]: Change
diff --git a/generic/tclZlib.c b/generic/tclZlib.c
index 47091de..ff887c8 100644
--- a/generic/tclZlib.c
+++ b/generic/tclZlib.c
@@ -3111,7 +3111,7 @@ ZlibTransformOutput(
 	e = deflate(&cd->outStream, Z_NO_FLUSH);
 	produced = cd->outAllocated - cd->outStream.avail_out;
 
-	if (e == Z_OK && cd->outStream.avail_out > 0) {
+	if (e == Z_OK && produced > 0) {
 	    if (Tcl_WriteRaw(cd->parent, cd->outBuffer, produced) < 0) {
 		*errorCodePtr = Tcl_GetErrno();
 		return -1;
diff --git a/tests/zlib.test b/tests/zlib.test
index 891dba0..96914ca 100644
--- a/tests/zlib.test
+++ b/tests/zlib.test
@@ -366,6 +366,25 @@ test zlib-8.15 {transformtion and fconfigure} -setup {
     catch {close $inSide}
     catch {$strm close}
 } -result {358 358}
+test zlib-8.16 {Bug 3603553: buffer transfer with large writes} -setup {
+    # Actual data isn't very important; needs to be substantially larger than
+    # the internal buffer (8kB) and incompressible.
+    set largeData {}
+    for {set i 0;expr srand(1)} {$i < 100000} {incr i} {
+	append largeData [lindex "a b c d e f g h i j k l m n o p" \
+		[expr {int(16*rand())}]]
+    }
+    set file [makeFile {} test.gz]
+} -constraints zlib -body {
+    set f [open $file wb]
+    fconfigure $f -buffering none
+    zlib push gzip $f
+    puts -nonewline $f $largeData
+    close $f
+    file size $file
+} -cleanup {
+    removeFile $file
+} -result 57647
 
 test zlib-9.1 "check fcopy with push" -constraints zlib -setup {
     set sfile [makeFile {} testsrc.gz]
-- 
cgit v0.12