From 935c25730a6f62bfbe0e0796bf4eae0a0d5f61d3 Mon Sep 17 00:00:00 2001 From: Daniele Varrazzo Date: Sat, 8 Jan 2011 09:54:18 +0000 Subject: [PATCH] Fixed segfault in large object close. Check that the connection is not closed/faulty before attempting lo_close. --- NEWS-2.3 | 4 +++- psycopg/lobject_int.c | 15 +++++++++++++++ tests/test_lobject.py | 9 +++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/NEWS-2.3 b/NEWS-2.3 index a8e20266..9518ca2a 100644 --- a/NEWS-2.3 +++ b/NEWS-2.3 @@ -7,12 +7,14 @@ What's new in psycopg 2.3.3 into Python tuples/namedtuples. - The build script refuses to guess values if pg_config is not found. - Connections and cursors are weakly referenceable. - - Fixed several reference leaks in less common code paths. * Bug fixes: - Fixed adaptation of None in composite types (ticket #26). Bug report by Karsten Hilbert. + - Fixed several reference leaks in less common code paths. + - Fixed segfault when a large object is closed and its connection no more + available. What's new in psycopg 2.3.2 diff --git a/psycopg/lobject_int.c b/psycopg/lobject_int.c index bac2afb6..c3ae662f 100644 --- a/psycopg/lobject_int.c +++ b/psycopg/lobject_int.c @@ -129,6 +129,21 @@ lobject_close_locked(lobjectObject *self, char **error) { int retvalue; + Dprintf("lobject_close_locked: conn->closed %ld", self->conn->closed); + switch (self->conn->closed) { + case 0: + /* Connection is open, go ahead */ + break; + case 1: + /* Connection is closed, return a success */ + return 0; + break; + default: + PyErr_SetString(OperationalError, "the connection is broken"); + return -1; + break; + } + if (self->conn->isolation_level == ISOLATION_LEVEL_AUTOCOMMIT || self->conn->mark != self->mark || self->fd == -1) diff --git a/tests/test_lobject.py b/tests/test_lobject.py index 056496ec..b3e38803 100755 --- a/tests/test_lobject.py +++ b/tests/test_lobject.py @@ -60,6 +60,10 @@ class LargeObjectMixin(object): def tearDown(self): if self.tmpdir: shutil.rmtree(self.tmpdir, ignore_errors=True) + + if self.conn.closed: + return + if self.lo_oid is not None: self.conn.rollback() try: @@ -106,6 +110,11 @@ class LargeObjectTests(LargeObjectMixin, unittest.TestCase): self.assertEqual(lo2.oid, lo.oid) self.assertEqual(lo2.closed, True) + def test_close_connection_gone(self): + lo = self.conn.lobject() + self.conn.close() + lo.close() + def test_create_with_oid(self): # Create and delete a large object to get an unused Oid. lo = self.conn.lobject()