From 22a80e7cb0f96b803b22ab3e908bf83d21704e7c Mon Sep 17 00:00:00 2001 From: "Michael W. Hudson" Date: Sun, 28 May 2006 15:51:40 +0000 Subject: [PATCH] Quality control, meet exceptions.c. Fix a number of problems with the need for speed code: One is doing this sort of thing: Py_DECREF(self->field); self->field = newval; Py_INCREF(self->field); without being very sure that self->field doesn't start with a value that has a __del__, because that almost certainly can lead to segfaults. As self->args is constrained to be an exact tuple we may as well exploit this fact consistently. This leads to quite a lot of simplification (and, hey, probably better performance). Add some error checking in places lacking it. Fix some rather strange indentation in the Unicode code. Delete some trailing whitespace. More to come, I haven't fixed all the reference leaks yet... --- Objects/exceptions.c | 233 +++++++++++++++++++------------------------ 1 file changed, 105 insertions(+), 128 deletions(-) diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 6271372efb3..4dd4cac5969 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -36,7 +36,7 @@ BaseException_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return NULL; } - self->message = PyString_FromString(""); + self->message = PyString_FromString(""); if (!self->message) { Py_DECREF(self); return NULL; @@ -53,9 +53,9 @@ BaseException_init(PyBaseExceptionObject *self, PyObject *args, PyObject *kwds) Py_INCREF(self->args); if (PyTuple_GET_SIZE(self->args) == 1) { - Py_DECREF(self->message); + Py_CLEAR(self->message); self->message = PyTuple_GET_ITEM(self->args, 0); - Py_INCREF(self->message); + Py_INCREF(self->message); } return 0; } @@ -79,8 +79,7 @@ BaseException_dealloc(PyBaseExceptionObject *self) int BaseException_traverse(PyBaseExceptionObject *self, visitproc visit, void *arg) { - if (self->dict) - Py_VISIT(self->dict); + Py_VISIT(self->dict); Py_VISIT(self->args); Py_VISIT(self->message); return 0; @@ -91,24 +90,13 @@ BaseException_str(PyBaseExceptionObject *self) { PyObject *out; - switch (PySequence_Length(self->args)) { + switch (PyTuple_GET_SIZE(self->args)) { case 0: out = PyString_FromString(""); break; case 1: - { - PyObject *tmp = PySequence_GetItem(self->args, 0); - if (tmp) { - out = PyObject_Str(tmp); - Py_DECREF(tmp); - } - else - out = NULL; + out = PyObject_Str(PyTuple_GET_ITEM(self->args, 0)); break; - } - case -1: - PyErr_Clear(); - /* Fall through */ default: out = PyObject_Str(self->args); break; @@ -120,28 +108,14 @@ BaseException_str(PyBaseExceptionObject *self) static PyObject * BaseException_repr(PyBaseExceptionObject *self) { - Py_ssize_t args_len; PyObject *repr_suffix; PyObject *repr; char *name; char *dot; - args_len = PySequence_Length(self->args); - if (args_len < 0) { + repr_suffix = PyObject_Repr(self->args); + if (!repr_suffix) return NULL; - } - - if (args_len == 0) { - repr_suffix = PyString_FromString("()"); - if (!repr_suffix) - return NULL; - } - else { - PyObject *args_repr = PyObject_Repr(self->args); - if (!args_repr) - return NULL; - repr_suffix = args_repr; - } name = (char *)self->ob_type->tp_name; dot = strrchr(name, '.'); @@ -172,18 +146,10 @@ BaseException_reduce(PyBaseExceptionObject *self) static PyObject * BaseException_unicode(PyBaseExceptionObject *self) { - if (PySequence_Length(self->args) == 0) + if (PyTuple_GET_SIZE(self->args) == 0) return PyUnicode_FromUnicode(NULL, 0); - if (PySequence_Length(self->args) == 1) { - PyObject *temp = PySequence_GetItem(self->args, 0); - PyObject *unicode_obj; - if (!temp) { - return NULL; - } - unicode_obj = PyObject_Unicode(temp); - Py_DECREF(temp); - return unicode_obj; - } + if (PyTuple_GET_SIZE(self->args) == 1) + return PyObject_Unicode(PyTuple_GET_ITEM(self->args, 0)); return PyObject_Unicode(self->args); } #endif /* Py_USING_UNICODE */ @@ -394,7 +360,7 @@ SimpleExtendsException(PyExc_BaseException, Exception, /* * StandardError extends Exception */ -SimpleExtendsException(PyExc_Exception, StandardError, +SimpleExtendsException(PyExc_Exception, StandardError, "Base class for all standard Python exceptions that do not represent\n" "interpreter exiting."); @@ -445,7 +411,9 @@ SystemExit_init(PySystemExitObject *self, PyObject *args, PyObject *kwds) if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) return -1; - Py_DECREF(self->code); + if (size == 0) + return 0; + Py_CLEAR(self->code); if (size == 1) self->code = PyTuple_GET_ITEM(args, 0); else if (size > 1) @@ -514,12 +482,9 @@ EnvironmentError_new(PyTypeObject *type, PyObject *args, PyObject *kwds) if (!self) return NULL; - self->myerrno = Py_None; - Py_INCREF(Py_None); - self->strerror = Py_None; - Py_INCREF(Py_None); - self->filename = Py_None; - Py_INCREF(Py_None); + MAKE_IT_NONE(self->myerrno); + MAKE_IT_NONE(self->strerror); + MAKE_IT_NONE(self->filename); return (PyObject *)self; } @@ -548,22 +513,22 @@ EnvironmentError_init(PyEnvironmentErrorObject *self, PyObject *args, if (PyTuple_GET_SIZE(args) <= 1) { return 0; } - - if (!PyArg_UnpackTuple(args, "EnvironmentError", 2, 3, + + if (!PyArg_UnpackTuple(args, "EnvironmentError", 2, 3, &myerrno, &strerror, &filename)) { return -1; } - Py_DECREF(self->myerrno); /* replacing */ + Py_CLEAR(self->myerrno); /* replacing */ self->myerrno = myerrno; Py_INCREF(self->myerrno); - Py_DECREF(self->strerror); /* replacing */ + Py_CLEAR(self->strerror); /* replacing */ self->strerror = strerror; Py_INCREF(self->strerror); /* self->filename will remain Py_None otherwise */ if (filename != NULL) { - Py_DECREF(self->filename); /* replacing */ + Py_CLEAR(self->filename); /* replacing */ self->filename = filename; Py_INCREF(self->filename); @@ -606,6 +571,9 @@ EnvironmentError_traverse(PyEnvironmentErrorObject *self, visitproc visit, static PyObject * EnvironmentError_str(PyEnvironmentErrorObject *self) { + /* XXX this needs to be rewritten to cope with any of self->filename, + self->strerror and self->myerrno being NULL. + */ PyObject *rtnval = NULL; if (self->filename != Py_None) { @@ -677,20 +645,17 @@ EnvironmentError_reduce(PyEnvironmentErrorObject *self) PyObject *res = NULL, *tmp; /* self->args is only the first two real arguments if there was a * file name given to EnvironmentError. */ - if (PyTuple_Check(args) && - PyTuple_GET_SIZE(args) == 2 && - self->filename != Py_None) { + if (PyTuple_GET_SIZE(args) == 2 && + self->filename != Py_None) { args = PyTuple_New(3); if (!args) return NULL; - - tmp = PyTuple_GetItem(self->args, 0); - if (!tmp) goto finish; + + tmp = PyTuple_GET_ITEM(self->args, 0); Py_INCREF(tmp); PyTuple_SET_ITEM(args, 0, tmp); - - tmp = PyTuple_GetItem(self->args, 1); - if (!tmp) goto finish; + + tmp = PyTuple_GET_ITEM(self->args, 1); Py_INCREF(tmp); PyTuple_SET_ITEM(args, 1, tmp); @@ -700,7 +665,6 @@ EnvironmentError_reduce(PyEnvironmentErrorObject *self) Py_INCREF(args); } res = PyTuple_Pack(3, self->ob_type, args, self->dict); - finish: Py_DECREF(args); return res; } @@ -714,14 +678,14 @@ static PyMethodDef EnvironmentError_methods[] = { ComplexExtendsException(PyExc_StandardError, EnvironmentError, EnvironmentError, EnvironmentError_dealloc, EnvironmentError_methods, EnvironmentError_members, - EnvironmentError_str, + EnvironmentError_str, "Base class for I/O related errors."); /* * IOError extends EnvironmentError */ -MiddlingExtendsException(PyExc_EnvironmentError, IOError, +MiddlingExtendsException(PyExc_EnvironmentError, IOError, EnvironmentError, "I/O operation failed."); @@ -783,6 +747,9 @@ WindowsError_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return (PyObject *)self; } + /* XXX this is dead code, surely? EnvironmentError_new always sets + self->myerrno to None! */ + /* Set errno to the POSIX errno, and winerror to the Win32 error code. */ errcode = PyInt_AsLong(self->myerrno); @@ -850,6 +817,8 @@ WindowsError_init(PyWindowsErrorObject *self, PyObject *args, PyObject *kwds) static PyObject * WindowsError_str(PyWindowsErrorObject *self) { + /* XXX this probably also needs to be rewritten to cope with NULL-ness of + the fields */ PyObject *repr = NULL; PyObject *fmt = NULL; PyObject *tuple = NULL; @@ -995,7 +964,7 @@ SyntaxError_init(PySyntaxErrorObject *self, PyObject *args, PyObject *kwds) return -1; if (lenargs >= 1) { - Py_DECREF(self->msg); + Py_CLEAR(self->msg); self->msg = PyTuple_GET_ITEM(args, 0); Py_INCREF(self->msg); } @@ -1004,21 +973,30 @@ SyntaxError_init(PySyntaxErrorObject *self, PyObject *args, PyObject *kwds) info = PySequence_Tuple(info); if (!info) return -1; - Py_DECREF(self->filename); + if (PyTuple_GET_SIZE(info) != 4) { + /* not a very good error message, but it's what Python 2.4 gives */ + PyErr_SetString(PyExc_IndexError, "tuple index out of range"); + Py_DECREF(info); + return -1; + } + + Py_CLEAR(self->filename); self->filename = PyTuple_GET_ITEM(info, 0); Py_INCREF(self->filename); - Py_DECREF(self->lineno); + Py_CLEAR(self->lineno); self->lineno = PyTuple_GET_ITEM(info, 1); Py_INCREF(self->lineno); - Py_DECREF(self->offset); + Py_CLEAR(self->offset); self->offset = PyTuple_GET_ITEM(info, 2); Py_INCREF(self->offset); - Py_DECREF(self->text); + Py_CLEAR(self->text); self->text = PyTuple_GET_ITEM(info, 3); Py_INCREF(self->text); + + Py_DECREF(info); } return 0; } @@ -1091,7 +1069,7 @@ SyntaxError_str(PySyntaxErrorObject *self) int have_lineno = 0; char *buffer = NULL; - have_filename = (self->filename != NULL) && + have_filename = (self->filename != NULL) && PyString_Check(self->filename); have_lineno = (self->lineno != NULL) && PyInt_Check(self->lineno); @@ -1196,9 +1174,8 @@ KeyError_str(PyBaseExceptionObject *self) string, that string will be displayed in quotes. Too bad. If args is anything else, use the default BaseException__str__(). */ - if (PyTuple_Check(self->args) && PyTuple_GET_SIZE(self->args) == 1) { - PyObject *key = PyTuple_GET_ITEM(self->args, 0); - return PyObject_Repr(key); + if (PyTuple_GET_SIZE(self->args) == 1) { + return PyObject_Repr(PyTuple_GET_ITEM(self->args, 0)); } return BaseException_str(self); } @@ -1531,7 +1508,7 @@ UnicodeError_init(PyUnicodeErrorObject *self, PyObject *args, PyObject *kwds, &PyInt_Type, &self->start, &PyInt_Type, &self->end, &PyString_Type, &self->reason)) { - self->encoding = self->object = self->start = self->end = + self->encoding = self->object = self->start = self->end = self->reason = NULL; return -1; } @@ -1616,27 +1593,27 @@ UnicodeEncodeError_str(PyObject *self) Py_ssize_t end; if (PyUnicodeEncodeError_GetStart(self, &start)) - return NULL; + return NULL; if (PyUnicodeEncodeError_GetEnd(self, &end)) - return NULL; + return NULL; if (end==start+1) { - int badchar = (int)PyUnicode_AS_UNICODE(((PyUnicodeErrorObject *)self)->object)[start]; - char badchar_str[20]; - if (badchar <= 0xff) - PyOS_snprintf(badchar_str, sizeof(badchar_str), "x%02x", badchar); - else if (badchar <= 0xffff) - PyOS_snprintf(badchar_str, sizeof(badchar_str), "u%04x", badchar); - else - PyOS_snprintf(badchar_str, sizeof(badchar_str), "U%08x", badchar); - return PyString_FromFormat( - "'%.400s' codec can't encode character u'\\%s' in position %zd: %.400s", - PyString_AS_STRING(((PyUnicodeErrorObject *)self)->encoding), - badchar_str, - start, - PyString_AS_STRING(((PyUnicodeErrorObject *)self)->reason) - ); + int badchar = (int)PyUnicode_AS_UNICODE(((PyUnicodeErrorObject *)self)->object)[start]; + char badchar_str[20]; + if (badchar <= 0xff) + PyOS_snprintf(badchar_str, sizeof(badchar_str), "x%02x", badchar); + else if (badchar <= 0xffff) + PyOS_snprintf(badchar_str, sizeof(badchar_str), "u%04x", badchar); + else + PyOS_snprintf(badchar_str, sizeof(badchar_str), "U%08x", badchar); + return PyString_FromFormat( + "'%.400s' codec can't encode character u'\\%s' in position %zd: %.400s", + PyString_AS_STRING(((PyUnicodeErrorObject *)self)->encoding), + badchar_str, + start, + PyString_AS_STRING(((PyUnicodeErrorObject *)self)->reason) + ); } return PyString_FromFormat( "'%.400s' codec can't encode characters in position %zd-%zd: %.400s", @@ -1668,7 +1645,7 @@ PyUnicodeEncodeError_Create( Py_ssize_t start, Py_ssize_t end, const char *reason) { return PyObject_CallFunction(PyExc_UnicodeEncodeError, "su#nns", - encoding, object, length, start, end, reason); + encoding, object, length, start, end, reason); } @@ -1703,17 +1680,17 @@ UnicodeDecodeError_str(PyObject *self) return NULL; if (end==start+1) { - /* FromFormat does not support %02x, so format that separately */ - char byte[4]; - PyOS_snprintf(byte, sizeof(byte), "%02x", - ((int)PyString_AS_STRING(((PyUnicodeErrorObject *)self)->object)[start])&0xff); - return PyString_FromFormat( - "'%.400s' codec can't decode byte 0x%s in position %zd: %.400s", - PyString_AS_STRING(((PyUnicodeErrorObject *)self)->encoding), - byte, - start, - PyString_AS_STRING(((PyUnicodeErrorObject *)self)->reason) - ); + /* FromFormat does not support %02x, so format that separately */ + char byte[4]; + PyOS_snprintf(byte, sizeof(byte), "%02x", + ((int)PyString_AS_STRING(((PyUnicodeErrorObject *)self)->object)[start])&0xff); + return PyString_FromFormat( + "'%.400s' codec can't decode byte 0x%s in position %zd: %.400s", + PyString_AS_STRING(((PyUnicodeErrorObject *)self)->encoding), + byte, + start, + PyString_AS_STRING(((PyUnicodeErrorObject *)self)->reason) + ); } return PyString_FromFormat( "'%.400s' codec can't decode bytes in position %zd-%zd: %.400s", @@ -1748,7 +1725,7 @@ PyUnicodeDecodeError_Create( assert(start < INT_MAX); assert(end < INT_MAX); return PyObject_CallFunction(PyExc_UnicodeDecodeError, "ss#nns", - encoding, object, length, start, end, reason); + encoding, object, length, start, end, reason); } @@ -1793,7 +1770,7 @@ UnicodeTranslateError_init(PyUnicodeErrorObject *self, PyObject *args, self->object = self->start = self->end = self->reason = NULL; return -1; } - + Py_INCREF(self->object); Py_INCREF(self->start); Py_INCREF(self->end); @@ -1810,26 +1787,26 @@ UnicodeTranslateError_str(PyObject *self) Py_ssize_t end; if (PyUnicodeTranslateError_GetStart(self, &start)) - return NULL; + return NULL; if (PyUnicodeTranslateError_GetEnd(self, &end)) - return NULL; + return NULL; if (end==start+1) { - int badchar = (int)PyUnicode_AS_UNICODE(((PyUnicodeErrorObject *)self)->object)[start]; - char badchar_str[20]; - if (badchar <= 0xff) - PyOS_snprintf(badchar_str, sizeof(badchar_str), "x%02x", badchar); - else if (badchar <= 0xffff) - PyOS_snprintf(badchar_str, sizeof(badchar_str), "u%04x", badchar); - else - PyOS_snprintf(badchar_str, sizeof(badchar_str), "U%08x", badchar); - return PyString_FromFormat( + int badchar = (int)PyUnicode_AS_UNICODE(((PyUnicodeErrorObject *)self)->object)[start]; + char badchar_str[20]; + if (badchar <= 0xff) + PyOS_snprintf(badchar_str, sizeof(badchar_str), "x%02x", badchar); + else if (badchar <= 0xffff) + PyOS_snprintf(badchar_str, sizeof(badchar_str), "u%04x", badchar); + else + PyOS_snprintf(badchar_str, sizeof(badchar_str), "U%08x", badchar); + return PyString_FromFormat( "can't translate character u'\\%s' in position %zd: %.400s", - badchar_str, - start, - PyString_AS_STRING(((PyUnicodeErrorObject *)self)->reason) - ); + badchar_str, + start, + PyString_AS_STRING(((PyUnicodeErrorObject *)self)->reason) + ); } return PyString_FromFormat( "can't translate characters in position %zd-%zd: %.400s", @@ -1860,7 +1837,7 @@ PyUnicodeTranslateError_Create( Py_ssize_t start, Py_ssize_t end, const char *reason) { return PyObject_CallFunction(PyExc_UnicodeTranslateError, "u#nns", - object, length, start, end, reason); + object, length, start, end, reason); } #endif @@ -2003,7 +1980,7 @@ static PyMethodDef functions[] = { Py_FatalError("Module dictionary insertion problem."); PyMODINIT_FUNC -_PyExc_Init(void) +_PyExc_Init(void) { PyObject *m, *bltinmod, *bdict;