[ 1229429 ] missing Py_DECREF in PyObject_CallMethod

Add a test in test_enumerate, which is a bit random, but suffices
(reversed_new calls PyObject_CallMethod under some circumstances).
This commit is contained in:
Michael W. Hudson 2005-07-12 10:21:19 +00:00
parent 208eec2cad
commit 0edc7a03e2
3 changed files with 36 additions and 8 deletions

View file

@ -1,4 +1,5 @@
import unittest import unittest
import sys
from test import test_support from test import test_support
@ -175,6 +176,25 @@ class TestReversed(unittest.TestCase):
self.assertRaises(TypeError, reversed) self.assertRaises(TypeError, reversed)
self.assertRaises(TypeError, reversed, [], 'extra') self.assertRaises(TypeError, reversed, [], 'extra')
def test_bug1229429(self):
# this bug was never in reversed, it was in
# PyObject_CallMethod, and reversed_new calls that sometimes.
if not hasattr(sys, "getrefcount"):
return
def f():
pass
r = f.__reversed__ = object()
rc = sys.getrefcount(r)
for i in range(10):
try:
reversed(f)
except TypeError:
pass
else:
self.fail("non-callable __reversed__ didn't raise!")
self.assertEqual(rc, sys.getrefcount(r))
def test_main(verbose=None): def test_main(verbose=None):
testclasses = (EnumerateTestCase, SubclassTestCase, TestEmpty, TestBig, testclasses = (EnumerateTestCase, SubclassTestCase, TestEmpty, TestBig,
TestReversed) TestReversed)

View file

@ -12,6 +12,9 @@ What's New in Python 2.5 alpha 1?
Core and builtins Core and builtins
----------------- -----------------
- SF bug #1229429: PyObject_CallMethod failed to decrement some
reference counts in some error exit cases.
- SF bug #1185883: Python's small-object memory allocator took over - SF bug #1185883: Python's small-object memory allocator took over
a block managed by the platform C library whenever a realloc specified a block managed by the platform C library whenever a realloc specified
a small new size. However, there's no portable way to know then how a small new size. However, there's no portable way to know then how

View file

@ -1797,7 +1797,9 @@ PyObject *
PyObject_CallMethod(PyObject *o, char *name, char *format, ...) PyObject_CallMethod(PyObject *o, char *name, char *format, ...)
{ {
va_list va; va_list va;
PyObject *args, *func = 0, *retval; PyObject *args = NULL;
PyObject *func = NULL;
PyObject *retval = NULL;
if (o == NULL || name == NULL) if (o == NULL || name == NULL)
return null_error(); return null_error();
@ -1808,8 +1810,10 @@ PyObject_CallMethod(PyObject *o, char *name, char *format, ...)
return 0; return 0;
} }
if (!PyCallable_Check(func)) if (!PyCallable_Check(func)) {
return type_error("call of non-callable attribute"); type_error("call of non-callable attribute");
goto exit;
}
if (format && *format) { if (format && *format) {
va_start(va, format); va_start(va, format);
@ -1820,23 +1824,24 @@ PyObject_CallMethod(PyObject *o, char *name, char *format, ...)
args = PyTuple_New(0); args = PyTuple_New(0);
if (!args) if (!args)
return NULL; goto exit;
if (!PyTuple_Check(args)) { if (!PyTuple_Check(args)) {
PyObject *a; PyObject *a;
a = PyTuple_New(1); a = PyTuple_New(1);
if (a == NULL) if (a == NULL)
return NULL; goto exit;
if (PyTuple_SetItem(a, 0, args) < 0) if (PyTuple_SetItem(a, 0, args) < 0)
return NULL; goto exit;
args = a; args = a;
} }
retval = PyObject_Call(func, args, NULL); retval = PyObject_Call(func, args, NULL);
Py_DECREF(args); exit:
Py_DECREF(func); Py_XDECREF(args);
Py_XDECREF(func);
return retval; return retval;
} }