Fixed segfault if COPY statements are executed

Close ticket #219
This commit is contained in:
Daniele Varrazzo 2014-06-06 21:21:39 +02:00
parent 115ceea1eb
commit 56adc590ff
3 changed files with 56 additions and 2 deletions

2
NEWS
View File

@ -13,6 +13,8 @@ Bug fixes:
What's new in psycopg 2.5.4 What's new in psycopg 2.5.4
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed segfault if COPY statements are executed instead of using the
proper methods (:ticket:`#219`).
- Don't ignore silently the `cursor.callproc` argument without a length. - Don't ignore silently the `cursor.callproc` argument without a length.

View File

@ -1288,6 +1288,13 @@ _pq_copy_in_v3(cursorObject *curs)
Py_ssize_t length = 0; Py_ssize_t length = 0;
int res, error = 0; int res, error = 0;
if (!curs->copyfile) {
PyErr_SetString(ProgrammingError,
"can't execute COPY FROM: use the copy_from() method instead");
error = 1;
goto exit;
}
if (!(func = PyObject_GetAttrString(curs->copyfile, "read"))) { if (!(func = PyObject_GetAttrString(curs->copyfile, "read"))) {
Dprintf("_pq_copy_in_v3: can't get o.read"); Dprintf("_pq_copy_in_v3: can't get o.read");
error = 1; error = 1;
@ -1411,7 +1418,8 @@ exit:
static int static int
_pq_copy_out_v3(cursorObject *curs) _pq_copy_out_v3(cursorObject *curs)
{ {
PyObject *tmp = NULL, *func; PyObject *tmp = NULL;
PyObject *func = NULL;
PyObject *obj = NULL; PyObject *obj = NULL;
int ret = -1; int ret = -1;
int is_text; int is_text;
@ -1419,6 +1427,12 @@ _pq_copy_out_v3(cursorObject *curs)
char *buffer; char *buffer;
Py_ssize_t len; Py_ssize_t len;
if (!curs->copyfile) {
PyErr_SetString(ProgrammingError,
"can't execute COPY TO: use the copy_to() method instead");
goto exit;
}
if (!(func = PyObject_GetAttrString(curs->copyfile, "write"))) { if (!(func = PyObject_GetAttrString(curs->copyfile, "write"))) {
Dprintf("_pq_copy_out_v3: can't get o.write"); Dprintf("_pq_copy_out_v3: can't get o.write");
goto exit; goto exit;

View File

@ -28,10 +28,13 @@ from testutils import unittest, ConnectingTestCase, decorate_all_tests
from testutils import skip_if_no_iobase, skip_before_postgres from testutils import skip_if_no_iobase, skip_before_postgres
from cStringIO import StringIO from cStringIO import StringIO
from itertools import cycle, izip from itertools import cycle, izip
from subprocess import Popen, PIPE
import psycopg2 import psycopg2
import psycopg2.extensions import psycopg2.extensions
from testutils import skip_copy_if_green from testutils import skip_copy_if_green, script_to_py3
from testconfig import dsn
if sys.version_info[0] < 3: if sys.version_info[0] < 3:
_base = object _base = object
@ -301,6 +304,41 @@ class CopyTests(ConnectingTestCase):
curs.copy_from, StringIO('aaa\nbbb\nccc\n'), 'tcopy') curs.copy_from, StringIO('aaa\nbbb\nccc\n'), 'tcopy')
self.assertEqual(curs.rowcount, -1) self.assertEqual(curs.rowcount, -1)
def test_copy_from_segfault(self):
# issue #219
script = ("""\
import psycopg2
conn = psycopg2.connect(%(dsn)r)
curs = conn.cursor()
curs.execute("create table copy_segf (id int)")
try:
curs.execute("copy copy_segf from stdin")
except psycopg2.ProgrammingError:
pass
conn.close()
""" % { 'dsn': dsn,})
proc = Popen([sys.executable, '-c', script_to_py3(script)])
proc.communicate()
self.assertEqual(0, proc.returncode)
def test_copy_to_segfault(self):
# issue #219
script = ("""\
import psycopg2
conn = psycopg2.connect(%(dsn)r)
curs = conn.cursor()
curs.execute("create table copy_segf (id int)")
try:
curs.execute("copy copy_segf to stdout")
except psycopg2.ProgrammingError:
pass
conn.close()
""" % { 'dsn': dsn,})
proc = Popen([sys.executable, '-c', script_to_py3(script)], stdout=PIPE)
proc.communicate()
self.assertEqual(0, proc.returncode)
decorate_all_tests(CopyTests, skip_copy_if_green) decorate_all_tests(CopyTests, skip_copy_if_green)