2007-09-12

Day 3 of my "Fix a bug each weekday" campaign

As I mentioned in a previous post I am seeing if I can help relax and unwind during the workday from the frustration that is Java by fixing Python bugs. Basically help make Python even better than Java (and thus lower my chances of using it more than required of me) and to atone for the fact that my thesis work uses Java instead of Python.

Yesterday I discovered that when I deprecated string exceptions 2.5 I missed the throw() method for generators. That meant 2.5 didn't raise a deprecation warning and 2.6 didn't raise an exception. I fixed it in 2.6 no problem. 2.5 I added the deprecation, although Guido questioned if that was smart since this will be for 2.5.2 and thus a micro release. It might be reverted in 2.5, but I say it should be there as you will get a nasty surprise come 2.6 since generator.throw("abc") will trigger a TypeError.

Today I got assigned a bug by Georg thanks to my infinite recursion fix that I applied on Monday. This one was supposedly over infinite recursion for bad super() calls. But then it got blamed on BaseException. What really turned out to be the issue, though, is that tuples and their __repr__ didn't check for any form of infinite recursion. Lists, for instance, check for a reference loop as it is not hard to do something like ``spam = []; spam.append(spam)``. You can also do something nuts like ``spam = [spam]`` 10,000 times. But both approaches are protected. Not so much for tuples. =)

You can't from Python source make a reference loop with a tuple. But it isn't hard to do in C code. Now you wouldn't think someone would do this, but it's still possible. BaseException, for instance, store a tuple for the arguments to its constructor. So if you create a subclass that calls BaseException.__init__(self, self) you now have a tuple that can reference itself through tuple.__repr__ since that will get the repr of each item in the tuple, which is self, which then has a reference to a argument tuple which that original tuple. Oops. =)

The str() issue was a little different. When you take the str() of a type it makes a call to that type's tp_str slot in the C code. Now normally that is not a problem and not a possible recursion issue. But BaseException triggered this by having the str of an exception be the first item in the argument tuple if it is the only item in that tuple. Since BaseException->tp_str calls the tp_str on the single item in the tuple (which is 'self' in this case), you get an infinite loop. Oops again.

Right now I am waiting on Georg to look over the patch to make sure my reasoning of doing these checks in tuple.__repr__ and _PyObject_Str() for the benefit of C code is the right thing to do instead of doing specific changes in BaseException. Then I have to see if I can come up with a possible unit test from Python code (probably will have to rely on BaseException's semantics).

In terms of trying to work on an issue each workday, it's actually feeling rather good. It's always nice to be able to help bring down the issue count by one (while it's probably being incremented by two or more that day =). Also gets me out of the big picture work I tend to do and back to basics.

And I even learn Roundup tricks in the process. Turns out that the "Your Details" page lists anything that was linked to your username (e.g., being assigned a bug). Helps make up for the loss of the SourceForge 30 day tracker history for your SF username.