Commit 7da83d32 authored by Jeremy Hylton's avatar Jeremy Hylton

Simplify and fix error handling for most cases.

Many functions used a local variable called return_error, which was
initialized to zero.  If an error occurred, it was set to true.  Most
of the code paths checked were only executed if return_error was
false.  goto is clearer.

The code also seemed to be written under the curious assumption that
calling Py_DECREF() on a local variable would assign the variable to
NULL.  As a result, more of the error-exit code paths returned an
object that had a reference count of zero instead of just returning
NULL.  Fixed the code to explicitly assign NULL after the DECREF.

A bit more reformatting, but not much.

XXX Need a much better test suite for zlib, since it the current tests
don't exercise any of this broken code.
parent 41a197c7
...@@ -136,7 +136,6 @@ PyZlib_compress(PyObject *self, PyObject *args) ...@@ -136,7 +136,6 @@ PyZlib_compress(PyObject *self, PyObject *args)
Byte *input, *output; Byte *input, *output;
int length, level=Z_DEFAULT_COMPRESSION, err; int length, level=Z_DEFAULT_COMPRESSION, err;
z_stream zst; z_stream zst;
int return_error;
PyObject * inputString; PyObject * inputString;
/* require Python string object, optional 'level' arg */ /* require Python string object, optional 'level' arg */
...@@ -149,9 +148,8 @@ PyZlib_compress(PyObject *self, PyObject *args) ...@@ -149,9 +148,8 @@ PyZlib_compress(PyObject *self, PyObject *args)
zst.avail_out = length + length/1000 + 12 + 1; zst.avail_out = length + length/1000 + 12 + 1;
output=(Byte*)malloc(zst.avail_out); output = (Byte*)malloc(zst.avail_out);
if (output==NULL) if (output == NULL) {
{
PyErr_SetString(PyExc_MemoryError, PyErr_SetString(PyExc_MemoryError,
"Can't allocate memory to compress data"); "Can't allocate memory to compress data");
return NULL; return NULL;
...@@ -162,35 +160,30 @@ PyZlib_compress(PyObject *self, PyObject *args) ...@@ -162,35 +160,30 @@ PyZlib_compress(PyObject *self, PyObject *args)
Py_INCREF(inputString); /* increment so that we hold ref */ Py_INCREF(inputString); /* increment so that we hold ref */
zst.zalloc=(alloc_func)NULL; zst.zalloc = (alloc_func)NULL;
zst.zfree=(free_func)Z_NULL; zst.zfree = (free_func)Z_NULL;
zst.next_out=(Byte *)output; zst.next_out = (Byte *)output;
zst.next_in =(Byte *)input; zst.next_in = (Byte *)input;
zst.avail_in=length; zst.avail_in = length;
err=deflateInit(&zst, level); err = deflateInit(&zst, level);
return_error = 0; switch(err) {
switch(err)
{
case(Z_OK): case(Z_OK):
break; break;
case(Z_MEM_ERROR): case(Z_MEM_ERROR):
PyErr_SetString(PyExc_MemoryError, PyErr_SetString(PyExc_MemoryError,
"Out of memory while compressing data"); "Out of memory while compressing data");
return_error = 1; goto error;
break;
case(Z_STREAM_ERROR): case(Z_STREAM_ERROR):
PyErr_SetString(ZlibError, PyErr_SetString(ZlibError,
"Bad compression level"); "Bad compression level");
return_error = 1; goto error;
break;
default: default:
deflateEnd(&zst); deflateEnd(&zst);
zlib_error(zst, err, "while compressing data"); zlib_error(zst, err, "while compressing data");
return_error = 1; goto error;
} }
if (!return_error) {
Py_BEGIN_ALLOW_THREADS; Py_BEGIN_ALLOW_THREADS;
err = deflate(&zst, Z_FINISH); err = deflate(&zst, Z_FINISH);
Py_END_ALLOW_THREADS; Py_END_ALLOW_THREADS;
...@@ -198,19 +191,17 @@ PyZlib_compress(PyObject *self, PyObject *args) ...@@ -198,19 +191,17 @@ PyZlib_compress(PyObject *self, PyObject *args)
if (err != Z_STREAM_END) { if (err != Z_STREAM_END) {
zlib_error(zst, err, "while compressing data"); zlib_error(zst, err, "while compressing data");
deflateEnd(&zst); deflateEnd(&zst);
return_error = 1; goto error;
} }
if (!return_error) {
err=deflateEnd(&zst); err=deflateEnd(&zst);
if (err == Z_OK) if (err == Z_OK)
ReturnVal = PyString_FromStringAndSize((char *)output, ReturnVal = PyString_FromStringAndSize((char *)output,
zst.total_out); zst.total_out);
else else
zlib_error(zst, err, "while finishing compression"); zlib_error(zst, err, "while finishing compression");
}
}
error:
free(output); free(output);
Py_DECREF(inputString); Py_DECREF(inputString);
...@@ -231,7 +222,6 @@ PyZlib_decompress(PyObject *self, PyObject *args) ...@@ -231,7 +222,6 @@ PyZlib_decompress(PyObject *self, PyObject *args)
int length, err; int length, err;
int wsize=DEF_WBITS, r_strlen=DEFAULTALLOC; int wsize=DEF_WBITS, r_strlen=DEFAULTALLOC;
z_stream zst; z_stream zst;
int return_error;
PyObject * inputString; PyObject * inputString;
if (!PyArg_ParseTuple(args, "S|ii:decompress", if (!PyArg_ParseTuple(args, "S|ii:decompress",
...@@ -260,24 +250,20 @@ PyZlib_decompress(PyObject *self, PyObject *args) ...@@ -260,24 +250,20 @@ PyZlib_decompress(PyObject *self, PyObject *args)
zst.next_in = (Byte *)input; zst.next_in = (Byte *)input;
err = inflateInit2(&zst, wsize); err = inflateInit2(&zst, wsize);
return_error = 0;
switch(err) { switch(err) {
case(Z_OK): case(Z_OK):
break; break;
case(Z_MEM_ERROR): case(Z_MEM_ERROR):
PyErr_SetString(PyExc_MemoryError, PyErr_SetString(PyExc_MemoryError,
"Out of memory while decompressing data"); "Out of memory while decompressing data");
return_error = 1; goto error;
default: default:
inflateEnd(&zst); inflateEnd(&zst);
zlib_error(zst, err, "while preparing to decompress data"); zlib_error(zst, err, "while preparing to decompress data");
return_error = 1; goto error;
} }
do { do {
if (return_error)
break;
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
err=inflate(&zst, Z_FINISH); err=inflate(&zst, Z_FINISH);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
...@@ -295,8 +281,7 @@ PyZlib_decompress(PyObject *self, PyObject *args) ...@@ -295,8 +281,7 @@ PyZlib_decompress(PyObject *self, PyObject *args)
PyErr_Format(ZlibError, "Error %i while decompressing data", PyErr_Format(ZlibError, "Error %i while decompressing data",
err); err);
inflateEnd(&zst); inflateEnd(&zst);
return_error = 1; goto error;
break;
} }
/* fall through */ /* fall through */
case(Z_OK): case(Z_OK):
...@@ -304,7 +289,7 @@ PyZlib_decompress(PyObject *self, PyObject *args) ...@@ -304,7 +289,7 @@ PyZlib_decompress(PyObject *self, PyObject *args)
if (_PyString_Resize(&result_str, r_strlen << 1) == -1) { if (_PyString_Resize(&result_str, r_strlen << 1) == -1) {
inflateEnd(&zst); inflateEnd(&zst);
result_str = NULL; result_str = NULL;
return_error = 1; goto error;
} }
zst.next_out = (unsigned char *)PyString_AsString(result_str) \ zst.next_out = (unsigned char *)PyString_AsString(result_str) \
+ r_strlen; + r_strlen;
...@@ -314,25 +299,24 @@ PyZlib_decompress(PyObject *self, PyObject *args) ...@@ -314,25 +299,24 @@ PyZlib_decompress(PyObject *self, PyObject *args)
default: default:
inflateEnd(&zst); inflateEnd(&zst);
zlib_error(zst, err, "while decompressing data"); zlib_error(zst, err, "while decompressing data");
return_error = 1; goto error;
} }
} while (err != Z_STREAM_END); } while (err != Z_STREAM_END);
if (!return_error) {
err = inflateEnd(&zst); err = inflateEnd(&zst);
if (err != Z_OK) { if (err != Z_OK) {
zlib_error(zst, err, "while finishing data decompression"); zlib_error(zst, err, "while finishing data decompression");
return NULL; return NULL;
} }
}
if (!return_error)
_PyString_Resize(&result_str, zst.total_out); _PyString_Resize(&result_str, zst.total_out);
else
Py_XDECREF(result_str); /* sets result_str == NULL, if not already */
Py_DECREF(inputString); Py_DECREF(inputString);
return result_str; return result_str;
error:
Py_DECREF(inputString);
Py_XDECREF(result_str);
return NULL;
} }
static PyObject * static PyObject *
...@@ -363,8 +347,7 @@ PyZlib_compressobj(PyObject *selfptr, PyObject *args) ...@@ -363,8 +347,7 @@ PyZlib_compressobj(PyObject *selfptr, PyObject *args)
return NULL; return NULL;
case(Z_STREAM_ERROR): case(Z_STREAM_ERROR):
Py_DECREF(self); Py_DECREF(self);
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError, "Invalid initialization option");
"Invalid initialization option");
return NULL; return NULL;
default: default:
zlib_error(self->zst, err, "while creating compression object"); zlib_error(self->zst, err, "while creating compression object");
...@@ -382,7 +365,7 @@ PyZlib_decompressobj(PyObject *selfptr, PyObject *args) ...@@ -382,7 +365,7 @@ PyZlib_decompressobj(PyObject *selfptr, PyObject *args)
return NULL; return NULL;
self = newcompobject(&Decomptype); self = newcompobject(&Decomptype);
if (self==NULL) if (self == NULL)
return(NULL); return(NULL);
self->zst.zalloc = (alloc_func)NULL; self->zst.zalloc = (alloc_func)NULL;
self->zst.zfree = (free_func)Z_NULL; self->zst.zfree = (free_func)Z_NULL;
...@@ -393,8 +376,7 @@ PyZlib_decompressobj(PyObject *selfptr, PyObject *args) ...@@ -393,8 +376,7 @@ PyZlib_decompressobj(PyObject *selfptr, PyObject *args)
return (PyObject*)self; return (PyObject*)self;
case(Z_STREAM_ERROR): case(Z_STREAM_ERROR):
Py_DECREF(self); Py_DECREF(self);
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError, "Invalid initialization option");
"Invalid initialization option");
return NULL; return NULL;
case (Z_MEM_ERROR): case (Z_MEM_ERROR):
Py_DECREF(self); Py_DECREF(self);
...@@ -451,11 +433,11 @@ PyZlib_objcompress(compobject *self, PyObject *args) ...@@ -451,11 +433,11 @@ PyZlib_objcompress(compobject *self, PyObject *args)
PyObject *RetVal; PyObject *RetVal;
Byte *input; Byte *input;
unsigned long start_total_out; unsigned long start_total_out;
int return_error; PyObject *inputString;
PyObject * inputString;
if (!PyArg_ParseTuple(args, "S:compress", &inputString)) if (!PyArg_ParseTuple(args, "S:compress", &inputString))
return NULL; return NULL;
if (PyString_AsStringAndSize(inputString, (char**)&input, &inplen) == -1) if (PyString_AsStringAndSize(inputString, (char**)&input, &inplen) == -1)
return NULL; return NULL;
...@@ -476,14 +458,12 @@ PyZlib_objcompress(compobject *self, PyObject *args) ...@@ -476,14 +458,12 @@ PyZlib_objcompress(compobject *self, PyObject *args)
err = deflate(&(self->zst), Z_NO_FLUSH); err = deflate(&(self->zst), Z_NO_FLUSH);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
return_error = 0;
/* while Z_OK and the output buffer is full, there might be more output, /* while Z_OK and the output buffer is full, there might be more output,
so extend the output buffer and try again */ so extend the output buffer and try again */
while (err == Z_OK && self->zst.avail_out == 0) { while (err == Z_OK && self->zst.avail_out == 0) {
if (_PyString_Resize(&RetVal, length << 1) == -1) { if (_PyString_Resize(&RetVal, length << 1) == -1) {
return_error = 1; RetVal = NULL;
break; goto error;
} }
self->zst.next_out = (unsigned char *)PyString_AsString(RetVal) \ self->zst.next_out = (unsigned char *)PyString_AsString(RetVal) \
+ length; + length;
...@@ -499,29 +479,19 @@ PyZlib_objcompress(compobject *self, PyObject *args) ...@@ -499,29 +479,19 @@ PyZlib_objcompress(compobject *self, PyObject *args)
condition. condition.
*/ */
if (!return_error) {
if (err != Z_OK && err != Z_BUF_ERROR) { if (err != Z_OK && err != Z_BUF_ERROR) {
if (self->zst.msg == Z_NULL) zlib_error(self->zst, err, "while compressing");
PyErr_Format(ZlibError, "Error %i while compressing",
err);
else
PyErr_Format(ZlibError, "Error %i while compressing: %.200s",
err, self->zst.msg);
return_error = 1;
Py_DECREF(RetVal); Py_DECREF(RetVal);
RetVal = NULL;
goto error;
} }
} if (_PyString_Resize(&RetVal,
self->zst.total_out - start_total_out) < 0)
if (return_error) RetVal = NULL;
RetVal = NULL; /* should have been handled by DECREF */
else
_PyString_Resize(&RetVal, self->zst.total_out - start_total_out);
error:
Py_DECREF(inputString); Py_DECREF(inputString);
LEAVE_ZLIB LEAVE_ZLIB
return RetVal; return RetVal;
} }
...@@ -544,7 +514,6 @@ PyZlib_objdecompress(compobject *self, PyObject *args) ...@@ -544,7 +514,6 @@ PyZlib_objdecompress(compobject *self, PyObject *args)
PyObject *RetVal; PyObject *RetVal;
Byte *input; Byte *input;
unsigned long start_total_out; unsigned long start_total_out;
int return_error;
PyObject * inputString; PyObject * inputString;
if (!PyArg_ParseTuple(args, "S|i:decompress", &inputString, &max_length)) if (!PyArg_ParseTuple(args, "S|i:decompress", &inputString, &max_length))
...@@ -565,7 +534,6 @@ PyZlib_objdecompress(compobject *self, PyObject *args) ...@@ -565,7 +534,6 @@ PyZlib_objdecompress(compobject *self, PyObject *args)
return NULL; return NULL;
ENTER_ZLIB ENTER_ZLIB
return_error = 0;
Py_INCREF(inputString); Py_INCREF(inputString);
...@@ -596,8 +564,8 @@ PyZlib_objdecompress(compobject *self, PyObject *args) ...@@ -596,8 +564,8 @@ PyZlib_objdecompress(compobject *self, PyObject *args)
length = max_length; length = max_length;
if (_PyString_Resize(&RetVal, length) == -1) { if (_PyString_Resize(&RetVal, length) == -1) {
return_error = 1; RetVal = NULL;
break; goto error;
} }
self->zst.next_out = (unsigned char *)PyString_AsString(RetVal) \ self->zst.next_out = (unsigned char *)PyString_AsString(RetVal) \
+ old_length; + old_length;
...@@ -614,8 +582,11 @@ PyZlib_objdecompress(compobject *self, PyObject *args) ...@@ -614,8 +582,11 @@ PyZlib_objdecompress(compobject *self, PyObject *args)
Py_DECREF(self->unconsumed_tail); Py_DECREF(self->unconsumed_tail);
self->unconsumed_tail = PyString_FromStringAndSize(self->zst.next_in, self->unconsumed_tail = PyString_FromStringAndSize(self->zst.next_in,
self->zst.avail_in); self->zst.avail_in);
if(!self->unconsumed_tail) if(!self->unconsumed_tail) {
return_error = 1; Py_DECREF(RetVal);
RetVal = NULL;
goto error;
}
} }
/* The end of the compressed data has been reached, so set the /* The end of the compressed data has been reached, so set the
...@@ -624,37 +595,29 @@ PyZlib_objdecompress(compobject *self, PyObject *args) ...@@ -624,37 +595,29 @@ PyZlib_objdecompress(compobject *self, PyObject *args)
inflateEnd, but the old behaviour of only calling it on flush() is inflateEnd, but the old behaviour of only calling it on flush() is
preserved. preserved.
*/ */
if (!return_error) {
if (err == Z_STREAM_END) { if (err == Z_STREAM_END) {
Py_XDECREF(self->unused_data); /* Free original empty string */ Py_XDECREF(self->unused_data); /* Free original empty string */
self->unused_data = PyString_FromStringAndSize( self->unused_data = PyString_FromStringAndSize(
(char *)self->zst.next_in, self->zst.avail_in); (char *)self->zst.next_in, self->zst.avail_in);
if (self->unused_data == NULL) { if (self->unused_data == NULL) {
Py_DECREF(RetVal); Py_DECREF(RetVal);
return_error = 1; goto error;
} }
/* We will only get Z_BUF_ERROR if the output buffer was full /* 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 but there wasn't more output when we tried again, so it is
not an error condition. not an error condition.
*/ */
} else if (err != Z_OK && err != Z_BUF_ERROR) { } else if (err != Z_OK && err != Z_BUF_ERROR) {
if (self->zst.msg == Z_NULL) zlib_error(self->zst, err, "while decompressing");
PyErr_Format(ZlibError, "Error %i while decompressing",
err);
else
PyErr_Format(ZlibError, "Error %i while decompressing: %.200s",
err, self->zst.msg);
Py_DECREF(RetVal); Py_DECREF(RetVal);
return_error = 1; RetVal = NULL;
} goto error;
} }
if (!return_error) { if (_PyString_Resize(&RetVal, self->zst.total_out - start_total_out) < 0)
_PyString_Resize(&RetVal, self->zst.total_out - start_total_out); RetVal = NULL;
}
else
RetVal = NULL; /* should be handled by DECREF */
error:
Py_DECREF(inputString); Py_DECREF(inputString);
LEAVE_ZLIB LEAVE_ZLIB
...@@ -677,7 +640,6 @@ PyZlib_flush(compobject *self, PyObject *args) ...@@ -677,7 +640,6 @@ PyZlib_flush(compobject *self, PyObject *args)
PyObject *RetVal; PyObject *RetVal;
int flushmode = Z_FINISH; int flushmode = Z_FINISH;
unsigned long start_total_out; unsigned long start_total_out;
int return_error;
if (!PyArg_ParseTuple(args, "|i:flush", &flushmode)) if (!PyArg_ParseTuple(args, "|i:flush", &flushmode))
return NULL; return NULL;
...@@ -702,14 +664,12 @@ PyZlib_flush(compobject *self, PyObject *args) ...@@ -702,14 +664,12 @@ PyZlib_flush(compobject *self, PyObject *args)
err = deflate(&(self->zst), flushmode); err = deflate(&(self->zst), flushmode);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
return_error = 0;
/* while Z_OK and the output buffer is full, there might be more output, /* while Z_OK and the output buffer is full, there might be more output,
so extend the output buffer and try again */ so extend the output buffer and try again */
while (err == Z_OK && self->zst.avail_out == 0) { while (err == Z_OK && self->zst.avail_out == 0) {
if (_PyString_Resize(&RetVal, length << 1) == -1) { if (_PyString_Resize(&RetVal, length << 1) == -1) {
return_error = 1; RetVal = NULL;
break; goto error;
} }
self->zst.next_out = (unsigned char *)PyString_AsString(RetVal) \ self->zst.next_out = (unsigned char *)PyString_AsString(RetVal) \
+ length; + length;
...@@ -724,21 +684,15 @@ PyZlib_flush(compobject *self, PyObject *args) ...@@ -724,21 +684,15 @@ PyZlib_flush(compobject *self, PyObject *args)
/* If flushmode is Z_FINISH, we also have to call deflateEnd() to free /* 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 various data structures. Note we should only get Z_STREAM_END when
flushmode is Z_FINISH, but checking both for safety*/ flushmode is Z_FINISH, but checking both for safety*/
if (!return_error) {
if (err == Z_STREAM_END && flushmode == Z_FINISH) { if (err == Z_STREAM_END && flushmode == Z_FINISH) {
err = deflateEnd(&(self->zst)); err = deflateEnd(&(self->zst));
if (err != Z_OK) { if (err != Z_OK) {
if (self->zst.msg == Z_NULL) zlib_error(self->zst, err, "from deflateEnd()");
PyErr_Format(ZlibError, "Error %i from deflateEnd()",
err);
else
PyErr_Format(ZlibError,
"Error %i from deflateEnd(): %.200s",
err, self->zst.msg);
Py_DECREF(RetVal); Py_DECREF(RetVal);
return_error = 1; RetVal = NULL;
} else goto error;
}
else
self->is_initialised = 0; self->is_initialised = 0;
/* We will only get Z_BUF_ERROR if the output buffer was full /* We will only get Z_BUF_ERROR if the output buffer was full
...@@ -746,23 +700,16 @@ PyZlib_flush(compobject *self, PyObject *args) ...@@ -746,23 +700,16 @@ PyZlib_flush(compobject *self, PyObject *args)
not an error condition. not an error condition.
*/ */
} else if (err!=Z_OK && err!=Z_BUF_ERROR) { } else if (err!=Z_OK && err!=Z_BUF_ERROR) {
if (self->zst.msg == Z_NULL) zlib_error(self->zst, err, "while flushing");
PyErr_Format(ZlibError, "Error %i while flushing",
err);
else
PyErr_Format(ZlibError, "Error %i while flushing: %.200s",
err, self->zst.msg);
Py_DECREF(RetVal); Py_DECREF(RetVal);
return_error = 1; RetVal = NULL;
}
} }
if (!return_error) if (_PyString_Resize(&RetVal, self->zst.total_out - start_total_out) < 0)
_PyString_Resize(&RetVal, self->zst.total_out - start_total_out); RetVal = NULL;
else
RetVal = NULL; /* should have been handled by DECREF */
LEAVE_ZLIB error:
LEAVE_ZLIB;
return RetVal; return RetVal;
} }
...@@ -780,7 +727,7 @@ PyZlib_unflush(compobject *self, PyObject *args) ...@@ -780,7 +727,7 @@ PyZlib_unflush(compobject *self, PyObject *args)
exceptions. This behaviour has been preserved.*/ exceptions. This behaviour has been preserved.*/
{ {
int err; int err;
PyObject * retval; PyObject * retval = NULL;
if (!PyArg_ParseTuple(args, "")) if (!PyArg_ParseTuple(args, ""))
return NULL; return NULL;
...@@ -788,10 +735,9 @@ PyZlib_unflush(compobject *self, PyObject *args) ...@@ -788,10 +735,9 @@ PyZlib_unflush(compobject *self, PyObject *args)
ENTER_ZLIB ENTER_ZLIB
err = inflateEnd(&(self->zst)); err = inflateEnd(&(self->zst));
if (err != Z_OK) { if (err != Z_OK)
zlib_error(self->zst, err, "from inflateEnd()"); zlib_error(self->zst, err, "from inflateEnd()");
retval = NULL; else {
} else {
self->is_initialised = 0; self->is_initialised = 0;
retval = PyString_FromStringAndSize(NULL, 0); retval = PyString_FromStringAndSize(NULL, 0);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment