osdir.com
mailing list archive F.A.Q. -since 2001!



Subject: Re: Pyrex exception type checking broken under
Python 2.5 (and earlier) - msg#00043

List: python.pyrex

Mail Archive Navigation:
by Date: Prev Next Date Index by Thread: Prev Next Thread Index

Hi Greg,

Greg Ewing wrote:
> Stefan Behnel wrote:
>> Pyrex uses this code in __Pyx_Raise() to check if an exception object
>> has the right type for being raised:
>>
>> The problem is that exceptions in Py2.5 have become new-style classes
>> which no longer fall under any of the above checks.
>>
>> Also, support for string exceptions is deprecated and supposed to be
>> removed in later Python versions. I therefore propose to actually
>> remove the above check from Pyrex completely.
>
> What I'd really like is an API call for raising an exception that
> does all the same things as the Python raise statement. There
> didn't seem to be such a call at the time I wrote that code.

There still doesn't seem to be a function that checks the argument types.


> I'd be wary about removing the checks altogether, because I
> wouldn't be surprised if you could cause a crash by stuffing
> arbitrary values into the exception variables.

I don't quite buy that argument - it's unlikely that it crashes, at least, and
having the Python interpreter raise exceptions for wrong arguments should be
fine. But since 2.5's interpreter actually checks for exception inheritance in
do_raise(), Pyrex can well do that, too.

Ok, so the only new thing is that instances of new-style classes are
'objects', just as new-style classes themselves. What Python 2.5 does is check
that they inherit from BaseException. Since that's not available in earlier
versions, what about checking that raised new-style objects (which are not
currently allowed at all in Pyrex) inherit from PyErr_Exception? I find that a
reasonable restriction.

The following is based on do_raise() in Py2.5. You can remove string support
completely by simply dropping the "if (PyString_CheckExact(type)) { } else"
part, however, Py*_CheckExact tends to be pretty fast, so there's not much you
loose by printing a warning as Py2.5 does.

I couldn't test it on earlier Python versions than 2.4, BTW, but it 'should'
work on 2.2.

Stefan


static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) {
Py_XINCREF(type);
Py_XINCREF(value);
Py_XINCREF(tb);
/* First, check the traceback argument, replacing None with NULL. */
if (tb == Py_None) {
Py_DECREF(tb);
tb = 0;
}
else if (tb != NULL && !PyTraceBack_Check(tb)) {
PyErr_SetString(PyExc_TypeError,
"raise: arg 3 must be a traceback or None");
goto raise_error;
}
/* Next, replace a missing value with None */
if (value == NULL) {
value = Py_None;
Py_INCREF(value);
}
/* Next, repeatedly, replace a tuple exception with its first item */
while (PyTuple_Check(type) && PyTuple_Size(type) > 0) {
PyObject *tmp = type;
type = PyTuple_GET_ITEM(type, 0);
Py_INCREF(type);
Py_DECREF(tmp);
}
if (PyString_CheckExact(type)) {
/* Raising builtin string is deprecated but still allowed --
* do nothing. Raising an instance of a new-style str
* subclass is right out. */
if (PyErr_Warn(PyExc_DeprecationWarning,
"raising a string exception is deprecated"))
goto raise_error;
}
else if (PyType_Check(type) || PyClass_Check(type))
; /* PyErr_NormalizeException(&type, &value, &tb); */
else if (PyInstance_Check(type)) {
/* Raising an instance. The value should be a dummy. */
if (value != Py_None) {
PyErr_SetString(PyExc_TypeError,
"instance exception may not have a separate value");
goto raise_error;
}
else {
/* Normalize to raise <class>, <instance> */
Py_DECREF(value);
value = type;
type = (PyObject*) ((PyInstanceObject*)type)->in_class;
Py_INCREF(type);
}
}
else if (PyType_IsSubtype(type->ob_type, (PyTypeObject*)PyExc_Exception)){
/* Raising a new-style object (in Py2.5).
The value should be a dummy. */
if (value != Py_None) {
PyErr_SetString(PyExc_TypeError,
"instance exception may not have a separate value");
goto raise_error;
}
else {
/* Normalize to raise <class>, <instance> */
Py_DECREF(value);
value = type;
type = type->ob_type;
Py_INCREF(type);
}
}
else {
/* Not something you can raise. You get an exception
anyway, just not what you specified :-) */
PyErr_Format(PyExc_TypeError,
"exceptions must be classes, instances, or "
"strings (deprecated), not %s",
type->ob_type->tp_name);
goto raise_error;
}
PyErr_Restore(type, value, tb);
return;
raise_error:
Py_XDECREF(value);
Py_XDECREF(type);
Py_XDECREF(tb);
return;
}


Thread at a glance:

Previous Message by Date:

Re: Pyrex exception type checking broken under Python 2.5 (and earlier)

Stefan Behnel wrote: > Pyrex uses this code in __Pyx_Raise() to check if an exception object has the > right type for being raised: > The problem is that exceptions in Py2.5 have become new-style classes which no > longer fall under any of the above checks. > Also, support for string exceptions is deprecated and supposed to be > removed in later Python versions. I therefore propose to actually remove the > above check from Pyrex completely. What I'd really like is an API call for raising an exception that does all the same things as the Python raise statement. There didn't seem to be such a call at the time I wrote that code. I'd be wary about removing the checks altogether, because I wouldn't be surprised if you could cause a crash by stuffing arbitrary values into the exception variables. It definitely needs updating for 2.5, though, and I take the point about string exceptions. I'll probably drop support for them. -- Greg

Next Message by Date:

Re: Pyrex exception type checking broken under Python 2.5 (and earlier)

Stefan Behnel wrote: > I don't quite buy that argument - it's unlikely that it crashes, at least Are you sure? That code is based on what the interpreter itself does for a raise statement, and if it's performing those checks, there's probably a reason for it. > What Python 2.5 does is check > that they inherit from BaseException. Since that's not available in earlier > versions, what about checking that raised new-style objects ... inherit from > PyErr_Exception? I find that a reasonable restriction. Yes, that sounds reasonable. I'll add this to my list. -- Greg

Previous Message by Thread:

Re: Pyrex exception type checking broken under Python 2.5 (and earlier)

Stefan Behnel wrote: > Pyrex uses this code in __Pyx_Raise() to check if an exception object has the > right type for being raised: > The problem is that exceptions in Py2.5 have become new-style classes which no > longer fall under any of the above checks. > Also, support for string exceptions is deprecated and supposed to be > removed in later Python versions. I therefore propose to actually remove the > above check from Pyrex completely. What I'd really like is an API call for raising an exception that does all the same things as the Python raise statement. There didn't seem to be such a call at the time I wrote that code. I'd be wary about removing the checks altogether, because I wouldn't be surprised if you could cause a crash by stuffing arbitrary values into the exception variables. It definitely needs updating for 2.5, though, and I take the point about string exceptions. I'll probably drop support for them. -- Greg

Next Message by Thread:

Re: Pyrex exception type checking broken under Python 2.5 (and earlier)

Stefan Behnel wrote: > I don't quite buy that argument - it's unlikely that it crashes, at least Are you sure? That code is based on what the interpreter itself does for a raise statement, and if it's performing those checks, there's probably a reason for it. > What Python 2.5 does is check > that they inherit from BaseException. Since that's not available in earlier > versions, what about checking that raised new-style objects ... inherit from > PyErr_Exception? I find that a reasonable restriction. Yes, that sounds reasonable. I'll add this to my list. -- Greg
blog comments powered by Disqus

Home | News | Sitemap | FAQ | advertise | OSDir is an Inevitable website. GBiz is too!