[Python-checkins] CVS: python/dist/src/Modules zlibmodule.c,2.38,2.39
A.M. Kuchling
akuchling@users.sourceforge.net
Tue, 20 Feb 2001 18:15:58 -0800
Update of /cvsroot/python/python/dist/src/Modules
In directory usw-pr-cvs1:/tmp/cvs-serv31686/Modules
Modified Files:
zlibmodule.c
Log Message:
Patch #103373 from Donovan Baarda: This patch:
* fixes the zlib decompress sync flush bug as reported in bug #124981
* avoids repeat calls to (in|de)flateEnd when destroying (de)compression
objects
* raises exception when allocating unused_data fails
* fixes memory leak when allocating unused_data fails
* raises exception when allocating decompress data fails
* removes vestigial code from decompress flush now that decompression
returns all available data
* tidies code so object compress/decompress/flush routines are consistent
Index: zlibmodule.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/zlibmodule.c,v
retrieving revision 2.38
retrieving revision 2.39
diff -C2 -r2.38 -r2.39
*** zlibmodule.c 2001/01/31 19:39:44 2.38
--- zlibmodule.c 2001/02/21 02:15:56 2.39
***************
*** 47,51 ****
newcompobject(PyTypeObject *type)
{
! compobject *self;
self = PyObject_New(compobject, type);
if (self == NULL)
--- 47,51 ----
newcompobject(PyTypeObject *type)
{
! compobject *self;
self = PyObject_New(compobject, type);
if (self == NULL)
***************
*** 382,386 ****
Decomp_dealloc(compobject *self)
{
! inflateEnd(&self->zst);
Py_XDECREF(self->unused_data);
PyObject_Del(self);
--- 382,387 ----
Decomp_dealloc(compobject *self)
{
! if (self->is_initialised)
! inflateEnd(&self->zst);
Py_XDECREF(self->unused_data);
PyObject_Del(self);
***************
*** 398,403 ****
PyZlib_objcompress(compobject *self, PyObject *args)
{
! int err = Z_OK, inplen;
! int length = DEFAULTALLOC;
PyObject *RetVal;
Byte *input;
--- 399,403 ----
PyZlib_objcompress(compobject *self, PyObject *args)
{
! int err, inplen, length = DEFAULTALLOC;
PyObject *RetVal;
Byte *input;
***************
*** 405,444 ****
if (!PyArg_ParseTuple(args, "s#:compress", &input, &inplen))
! return NULL;
! self->zst.avail_in = inplen;
! self->zst.next_in = input;
if (!(RetVal = PyString_FromStringAndSize(NULL, length))) {
! PyErr_SetString(PyExc_MemoryError,
! "Can't allocate memory to compress data");
! return NULL;
}
start_total_out = self->zst.total_out;
! self->zst.next_out = (unsigned char *)PyString_AsString(RetVal);
self->zst.avail_out = length;
! while (self->zst.avail_in != 0 && err == Z_OK)
! {
! err = deflate(&(self->zst), Z_NO_FLUSH);
! if (self->zst.avail_out <= 0) {
! if (_PyString_Resize(&RetVal, length << 1) == -1) {
! PyErr_SetString(PyExc_MemoryError,
! "Can't allocate memory to compress data");
! return NULL;
! }
! self->zst.next_out = (unsigned char *)PyString_AsString(RetVal) + length;
! self->zst.avail_out = length;
! length = length << 1;
! }
! }
! if (err != Z_OK)
! {
! if (self->zst.msg == Z_NULL)
! PyErr_Format(ZlibError, "Error %i while compressing",
! err);
! else
! PyErr_Format(ZlibError, "Error %i while compressing: %.200s",
! err, self->zst.msg);
! Py_DECREF(RetVal);
return NULL;
}
_PyString_Resize(&RetVal, self->zst.total_out - start_total_out);
return RetVal;
--- 405,445 ----
if (!PyArg_ParseTuple(args, "s#:compress", &input, &inplen))
! return NULL;
if (!(RetVal = PyString_FromStringAndSize(NULL, length))) {
! PyErr_SetString(PyExc_MemoryError,
! "Can't allocate memory to compress data");
! return NULL;
}
start_total_out = self->zst.total_out;
! self->zst.avail_in = inplen;
! self->zst.next_in = input;
self->zst.avail_out = length;
! self->zst.next_out = (unsigned char *)PyString_AsString(RetVal);
! err = deflate(&(self->zst), Z_NO_FLUSH);
! /* while Z_OK and the output buffer is full, there might be more output,
! so extend the output buffer and try again */
! while (err == Z_OK && self->zst.avail_out == 0) {
! if (_PyString_Resize(&RetVal, length << 1) == -1) {
! PyErr_SetString(PyExc_MemoryError,
! "Can't allocate memory to compress data");
return NULL;
}
+ self->zst.next_out = (unsigned char *)PyString_AsString(RetVal) + length;
+ self->zst.avail_out = length;
+ length = length << 1;
+ err = deflate(&(self->zst), Z_NO_FLUSH);
+ }
+ /* We will only get Z_BUF_ERROR if the output buffer was full but there
+ wasn't more output when we tried again, so it is not an error condition */
+ if (err != Z_OK && err != Z_BUF_ERROR) {
+ if (self->zst.msg == Z_NULL)
+ PyErr_Format(ZlibError, "Error %i while compressing",
+ err);
+ else
+ PyErr_Format(ZlibError, "Error %i while compressing: %.200s",
+ err, self->zst.msg);
+ Py_DECREF(RetVal);
+ return NULL;
+ }
_PyString_Resize(&RetVal, self->zst.total_out - start_total_out);
return RetVal;
***************
*** 455,459 ****
PyZlib_objdecompress(compobject *self, PyObject *args)
{
! int length, err, inplen;
PyObject *RetVal;
Byte *input;
--- 456,460 ----
PyZlib_objdecompress(compobject *self, PyObject *args)
{
! int err, inplen, length = DEFAULTALLOC;
PyObject *RetVal;
Byte *input;
***************
*** 462,515 ****
if (!PyArg_ParseTuple(args, "s#:decompress", &input, &inplen))
return NULL;
start_total_out = self->zst.total_out;
- RetVal = PyString_FromStringAndSize(NULL, DEFAULTALLOC);
self->zst.avail_in = inplen;
self->zst.next_in = input;
! self->zst.avail_out = length = DEFAULTALLOC;
self->zst.next_out = (unsigned char *)PyString_AsString(RetVal);
! err = Z_OK;
!
! while (self->zst.avail_in != 0 && err == Z_OK)
! {
! err = inflate(&(self->zst), Z_NO_FLUSH);
! if (err == Z_OK && self->zst.avail_out <= 0)
! {
! if (_PyString_Resize(&RetVal, length << 1) == -1)
! {
! PyErr_SetString(PyExc_MemoryError,
! "Can't allocate memory to compress data");
! return NULL;
! }
! self->zst.next_out = (unsigned char *)PyString_AsString(RetVal) + length;
! self->zst.avail_out = length;
! length = length << 1;
! }
! }
!
! if (err != Z_OK && err != Z_STREAM_END)
! {
! if (self->zst.msg == Z_NULL)
! PyErr_Format(ZlibError, "Error %i while decompressing",
! err);
! else
! PyErr_Format(ZlibError, "Error %i while decompressing: %.200s",
! err, self->zst.msg);
Py_DECREF(RetVal);
return NULL;
}
!
! if (err == Z_STREAM_END)
! {
! /* The end of the compressed data has been reached, so set
! the unused_data attribute to a string containing the
! remainder of the data in the string. */
! int pos = self->zst.next_in - input; /* Position in the string */
! Py_XDECREF(self->unused_data); /* Free the original, empty string */
!
! self->unused_data = PyString_FromStringAndSize((char *)input+pos,
! inplen-pos);
! if (self->unused_data == NULL) return NULL;
}
-
_PyString_Resize(&RetVal, self->zst.total_out - start_total_out);
return RetVal;
--- 463,516 ----
if (!PyArg_ParseTuple(args, "s#:decompress", &input, &inplen))
return NULL;
+ if (!(RetVal = PyString_FromStringAndSize(NULL, length))) {
+ PyErr_SetString(PyExc_MemoryError,
+ "Can't allocate memory to compress data");
+ return NULL;
+ }
start_total_out = self->zst.total_out;
self->zst.avail_in = inplen;
self->zst.next_in = input;
! self->zst.avail_out = length;
self->zst.next_out = (unsigned char *)PyString_AsString(RetVal);
! err = inflate(&(self->zst), Z_SYNC_FLUSH);
! /* while Z_OK and the output buffer is full, there might be more output,
! so extend the output buffer and try again */
! while (err == Z_OK && self->zst.avail_out == 0) {
! if (_PyString_Resize(&RetVal, length << 1) == -1) {
! PyErr_SetString(PyExc_MemoryError,
! "Can't allocate memory to compress data");
! return NULL;
! }
! self->zst.next_out = (unsigned char *)PyString_AsString(RetVal) + length;
! self->zst.avail_out = length;
! length = length << 1;
! err = inflate(&(self->zst), Z_SYNC_FLUSH);
! }
! /* The end of the compressed data has been reached, so set the unused_data
! attribute to a string containing the remainder of the data in the string.
! Note that this is also a logical place to call inflateEnd, but the old
! behaviour of only calling it on flush() is preserved.*/
! if (err == Z_STREAM_END) {
! Py_XDECREF(self->unused_data); /* Free the original, empty string */
! self->unused_data = PyString_FromStringAndSize(self->zst.next_in,
! self->zst.avail_in);
! if (self->unused_data == NULL) {
! PyErr_SetString(PyExc_MemoryError,
! "Can't allocate memory to unused_data");
Py_DECREF(RetVal);
return NULL;
}
! /* We will only get Z_BUF_ERROR if the output buffer was full but there
! wasn't more output when we tried again, so it is not an error condition */
! } else if (err != Z_OK && err != Z_BUF_ERROR) {
! if (self->zst.msg == Z_NULL)
! PyErr_Format(ZlibError, "Error %i while decompressing",
! err);
! else
! PyErr_Format(ZlibError, "Error %i while decompressing: %.200s",
! err, self->zst.msg);
! Py_DECREF(RetVal);
! return NULL;
}
_PyString_Resize(&RetVal, self->zst.total_out - start_total_out);
return RetVal;
***************
*** 527,531 ****
PyZlib_flush(compobject *self, PyObject *args)
{
! int length=DEFAULTALLOC, err = Z_OK;
PyObject *RetVal;
int flushmode = Z_FINISH;
--- 528,532 ----
PyZlib_flush(compobject *self, PyObject *args)
{
! int err, length=DEFAULTALLOC;
PyObject *RetVal;
int flushmode = Z_FINISH;
***************
*** 533,602 ****
if (!PyArg_ParseTuple(args, "|i:flush", &flushmode))
! return NULL;
/* Flushing with Z_NO_FLUSH is a no-op, so there's no point in
doing any work at all; just return an empty string. */
! if (flushmode == Z_NO_FLUSH)
! {
! return PyString_FromStringAndSize(NULL, 0);
! }
- self->zst.avail_in = 0;
- self->zst.next_in = Z_NULL;
if (!(RetVal = PyString_FromStringAndSize(NULL, length))) {
! PyErr_SetString(PyExc_MemoryError,
! "Can't allocate memory to compress data");
! return NULL;
}
start_total_out = self->zst.total_out;
! self->zst.next_out = (unsigned char *)PyString_AsString(RetVal);
self->zst.avail_out = length;
!
! /* When flushing the zstream, there's no input data.
! If zst.avail_out == 0, that means that more output space is
! needed to complete the flush operation. */
! while (1) {
! err = deflate(&(self->zst), flushmode);
!
! /* If the output is Z_OK, and there's still room in the output
! buffer, then the flush is complete. */
! if ( (err == Z_OK) && self->zst.avail_out > 0) break;
!
! /* A nonzero return indicates some sort of error (but see
! the comment for the error handler below) */
! if ( err != Z_OK ) break;
!
! /* There's no space left for output, so increase the buffer and loop
! again */
! if (_PyString_Resize(&RetVal, length << 1) == -1) {
! PyErr_SetString(PyExc_MemoryError,
! "Can't allocate memory to compress data");
! return NULL;
! }
! self->zst.next_out = (unsigned char *)PyString_AsString(RetVal) + length;
! self->zst.avail_out = length;
! length = length << 1;
! }
!
! /* Raise an exception indicating an error. The condition for
! detecting a error is kind of complicated; Z_OK indicates no
! error, but if the flushmode is Z_FINISH, then Z_STREAM_END is
! also not an error. */
! if (err!=Z_OK && !(flushmode == Z_FINISH && err == Z_STREAM_END) )
! {
! if (self->zst.msg == Z_NULL)
! PyErr_Format(ZlibError, "Error %i while flushing",
! err);
! else
! PyErr_Format(ZlibError, "Error %i while flushing: %.200s",
! err, self->zst.msg);
! Py_DECREF(RetVal);
return NULL;
! }
!
! /* If flushmode is Z_FINISH, we also have to call deflateEnd() to
! free various data structures */
!
! if (flushmode == Z_FINISH) {
err=deflateEnd(&(self->zst));
if (err!=Z_OK) {
--- 534,572 ----
if (!PyArg_ParseTuple(args, "|i:flush", &flushmode))
! return NULL;
/* Flushing with Z_NO_FLUSH is a no-op, so there's no point in
doing any work at all; just return an empty string. */
! if (flushmode == Z_NO_FLUSH) {
! return PyString_FromStringAndSize(NULL, 0);
! }
if (!(RetVal = PyString_FromStringAndSize(NULL, length))) {
! PyErr_SetString(PyExc_MemoryError,
! "Can't allocate memory to compress data");
! return NULL;
}
start_total_out = self->zst.total_out;
! self->zst.avail_in = 0;
self->zst.avail_out = length;
! self->zst.next_out = (unsigned char *)PyString_AsString(RetVal);
! err = deflate(&(self->zst), flushmode);
! /* while Z_OK and the output buffer is full, there might be more output,
! so extend the output buffer and try again */
! while (err == Z_OK && self->zst.avail_out == 0) {
! if (_PyString_Resize(&RetVal, length << 1) == -1) {
! PyErr_SetString(PyExc_MemoryError,
! "Can't allocate memory to compress data");
return NULL;
! }
! self->zst.next_out = (unsigned char *)PyString_AsString(RetVal) + length;
! self->zst.avail_out = length;
! length = length << 1;
! err = deflate(&(self->zst), flushmode);
! }
! /* If flushmode is Z_FINISH, we also have to call deflateEnd() to free
! various data structures. Note we should only get Z_STREAM_END when
! flushmode is Z_FINISH, but checking both for safety*/
! if (err == Z_STREAM_END && flushmode == Z_FINISH) {
err=deflateEnd(&(self->zst));
if (err!=Z_OK) {
***************
*** 605,614 ****
err);
else
! PyErr_Format(ZlibError,
! "Error %i from deflateEnd(): %.200s",
err, self->zst.msg);
Py_DECREF(RetVal);
return NULL;
}
}
_PyString_Resize(&RetVal, self->zst.total_out - start_total_out);
--- 575,595 ----
err);
else
! PyErr_Format(ZlibError,"Error %i from deflateEnd(): %.200s",
err, self->zst.msg);
Py_DECREF(RetVal);
return NULL;
}
+ self->is_initialised = 0;
+ /* We will only get Z_BUF_ERROR if the output buffer was full but there
+ wasn't more output when we tried again, so it is not an error condition */
+ } else if (err!=Z_OK && err!=Z_BUF_ERROR) {
+ if (self->zst.msg == Z_NULL)
+ PyErr_Format(ZlibError, "Error %i while flushing",
+ err);
+ else
+ PyErr_Format(ZlibError, "Error %i while flushing: %.200s",
+ err, self->zst.msg);
+ Py_DECREF(RetVal);
+ return NULL;
}
_PyString_Resize(&RetVal, self->zst.total_out - start_total_out);
***************
*** 623,691 ****
static PyObject *
PyZlib_unflush(compobject *self, PyObject *args)
{
! int length=0, err;
! PyObject *RetVal;
if (!PyArg_ParseTuple(args, ""))
! return NULL;
! if (!(RetVal = PyString_FromStringAndSize(NULL, DEFAULTALLOC)))
! {
! PyErr_SetString(PyExc_MemoryError,
! "Can't allocate memory to decompress data");
! return NULL;
! }
! self->zst.avail_in=0;
! self->zst.next_out = (unsigned char *)PyString_AsString(RetVal);
! length = self->zst.avail_out = DEFAULTALLOC;
!
! /* I suspect that Z_BUF_ERROR is the only error code we need to check for
! in the following loop, but will leave the Z_OK in for now to avoid
! destabilizing this function. --amk */
! err = Z_OK;
! while ( err == Z_OK )
! {
! err = inflate(&(self->zst), Z_FINISH);
! if ( ( err == Z_OK || err == Z_BUF_ERROR ) && self->zst.avail_out == 0)
! {
! if (_PyString_Resize(&RetVal, length << 1) == -1)
! {
! PyErr_SetString(PyExc_MemoryError,
! "Can't allocate memory to decompress data");
! return NULL;
! }
! self->zst.next_out = (unsigned char *)PyString_AsString(RetVal) + length;
! self->zst.avail_out = length;
! length = length << 1;
! err = Z_OK;
! }
! }
! if (err!=Z_STREAM_END)
! {
! if (self->zst.msg == Z_NULL)
! PyErr_Format(ZlibError, "Error %i while decompressing",
! err);
! else
! PyErr_Format(ZlibError, "Error %i while decompressing: %.200s",
! err, self->zst.msg);
! Py_DECREF(RetVal);
! return NULL;
! }
err=inflateEnd(&(self->zst));
! if (err!=Z_OK)
! {
! if (self->zst.msg == Z_NULL)
! PyErr_Format(ZlibError,
! "Error %i while flushing decompression object",
! err);
! else
! PyErr_Format(ZlibError,
! "Error %i while flushing decompression object: %.200s",
! err, self->zst.msg);
! Py_DECREF(RetVal);
! return NULL;
}
! _PyString_Resize(&RetVal,
! (char *)self->zst.next_out - PyString_AsString(RetVal));
! return RetVal;
}
--- 604,628 ----
static PyObject *
PyZlib_unflush(compobject *self, PyObject *args)
+ /*decompressor flush is a no-op because all pending data would have been
+ flushed by the decompress method. However, this routine previously called
+ inflateEnd, causing any further decompress or flush calls to raise
+ exceptions. This behaviour has been preserved.*/
{
! int err;
if (!PyArg_ParseTuple(args, ""))
! return NULL;
err=inflateEnd(&(self->zst));
! if (err!=Z_OK) {
! if (self->zst.msg == Z_NULL)
! PyErr_Format(ZlibError, "Error %i from inflateEnd()",
! err);
! else
! PyErr_Format(ZlibError, "Error %i from inflateEnd(): %.200s",
! err, self->zst.msg);
! return NULL;
}
! self->is_initialised = 0;
! return PyString_FromStringAndSize(NULL, 0);
}