Don't segfault on uninitialized cursor

It can happen with bad cursor subclasses not calling super's init. Raise
an exception instead of segfaulting.

Closes #195
This commit is contained in:
Daniele Varrazzo 2014-02-26 19:37:59 +00:00
parent 618f7e41de
commit 7b82be936d
3 changed files with 22 additions and 3 deletions

2
NEWS
View File

@ -17,6 +17,8 @@ What's new in psycopg 2.5.3
Chris Withers (:ticket:`#193`). Chris Withers (:ticket:`#193`).
- Avoid blocking async connections on connect (:ticket:`#194`). Thanks to - Avoid blocking async connections on connect (:ticket:`#194`). Thanks to
Adam Petrovich for the bug report and diagnosis. Adam Petrovich for the bug report and diagnosis.
- Don't segfault using poorly defined cursor subclasses which forgot to call
the superclass init (:ticket:`#195`).
- Fixed debug build on Windows, thanks to James Emerton. - Fixed debug build on Windows, thanks to James Emerton.

View File

@ -97,11 +97,14 @@ HIDDEN int psyco_curs_scrollable_set(cursorObject *self, PyObject *pyvalue);
/* exception-raising macros */ /* exception-raising macros */
#define EXC_IF_CURS_CLOSED(self) \ #define EXC_IF_CURS_CLOSED(self) \
do \ do { \
if ((self)->closed || ((self)->conn && (self)->conn->closed)) { \ if (!(self)->conn) { \
PyErr_SetString(InterfaceError, "the cursor has no connection"); \
return NULL; } \
if ((self)->closed || (self)->conn->closed) { \
PyErr_SetString(InterfaceError, "cursor already closed"); \ PyErr_SetString(InterfaceError, "cursor already closed"); \
return NULL; } \ return NULL; } \
while (0) } while (0)
#define EXC_IF_NO_TUPLES(self) \ #define EXC_IF_NO_TUPLES(self) \
do \ do \

View File

@ -413,6 +413,20 @@ class CursorTests(ConnectingTestCase):
cur.scroll(9, mode='absolute') cur.scroll(9, mode='absolute')
self.assertEqual(cur.fetchone(), (9,)) self.assertEqual(cur.fetchone(), (9,))
def test_bad_subclass(self):
# check that we get an error message instead of a segfault
# for badly written subclasses.
# see http://stackoverflow.com/questions/22019341/
class StupidCursor(psycopg2.extensions.cursor):
def __init__(self, *args, **kwargs):
# I am stupid so not calling superclass init
pass
cur = StupidCursor()
self.assertRaises(psycopg2.InterfaceError, cur.execute, 'select 1')
self.assertRaises(psycopg2.InterfaceError, cur.executemany,
'select 1', [])
def test_suite(): def test_suite():
return unittest.TestLoader().loadTestsFromName(__name__) return unittest.TestLoader().loadTestsFromName(__name__)