[Python-Dev] Strange bug only happens with Python 2.2

Guido van Rossum guido@python.org
Fri, 27 Sep 2002 12:04:01 -0400

> This is somewhat off-topic, but I'm hoping maybe someone can give a hint
> why this only happens on Python 2.2.1.
> Ok, here's the story:
> I've had a bug report against our pyPgSQL database interface package that
> retrieving Large Objects doesn't work with Python 2.2.1. The reproducible
> traceback we get is:
> Traceback (most recent call last):
>   File "p.py", line 20, in ?
>     res = cs.fetchone()
>   File "pyPgSQL/PgSQL.py", line 2672, in fetchone
>     return self.__fetchOneRow()
>   File "pyPgSQL/PgSQL.py", line 2281, in __fetchOneRow
>     for _i in range(self.res.nfields):
> AttributeError: 'str' object has no attribute '__bases__'
> This traceback is quite obviously bogus, as self.res.nfields is a Python
> int and no strings are involved here whatsoever. After some debugging, I
> found that something very strange happens in a function call that
> happens in this for loop. Inside the for loop, a function typecast is
> called, which has this code within:
> if isinstance(value, PgBytea) or type(value) is PgLargeObjectType:
> This code is causing the problems which result in the bogus traceback
> later on.
> Now in my case, 'value' is of type PgLargeObjectType, which is a custom
> type from our extension module. PgBytea is a Python class.
> Now comes the first very strange observation: Swapping the checks, so
> that the 'type(value) is PgLargeObjectType' check comes first makes the
> problem go away. So my conclusion is that there's some problem with
> isinstance and my custom extension type.
> The second strange thing is that this only happens on Python 2.2.1
> (Linux, FreeBSD, Windows), but _not_ on Python 2.1.3 or Python 2.3-CVS.
> Oh, the problem isn't tied to isinstance(value, PgBytea). Any isinstance
> check causes it later on.
> Of course I'm suspecting that there's some problem with the extension
> type. Looks like some internal interpreter data gets corrupted. No idea
> how to debug that, too.
> Does anybody have any tips where to look or how to debug this further?

Probably some C code receives an exception and decides to go a
different path (rather than propagating the exception), but forgets to
call PyErr_Clear().

If you call some other code that raises an exception or calls
PyErr_Clear(), the spurious exception is gone; but if you call some
other code that *tests* for an exception (usually with
PyExc_Occurred() or PyErr_ExceptionMatches()), that code may raise the
bogus exception at an unexpected place.

So I'd look in your extension for places where it tests for an
exception and decides to ignore it but forgets to clear it.

It's also possible that this occurs in the Python code (have you tried
the 2.2.2 CVS?  Use "cvs update -r release22-maint") but if I had to
bet, I'd bet on your SQL extension. :-)

--Guido van Rossum (home page: http://www.python.org/~guido/)