From 2f7b286a8ce74fbfaa8d2170d457308c6a62e870 Mon Sep 17 00:00:00 2001 From: Vinay Sajip Date: Fri, 3 Feb 2012 18:23:05 +0000 Subject: [PATCH 1/3] Revert fix for #13807 mistakenly applied in this branch. --- Lib/logging/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py index f70dfb5239d..685efeb4a88 100644 --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -721,7 +721,7 @@ def handleError(self, record): You could, however, replace this with a custom handler if you wish. The record which was being processed is passed in to this method. """ - if raiseExceptions and sys.stderr: # see issue 13807 + if raiseExceptions: ei = sys.exc_info() try: traceback.print_exception(ei[0], ei[1], ei[2], None, sys.stderr) From 77940902512c85e2d09dd5bd913084dc547881ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Charles-Fran=C3=A7ois=20Natali?= Date: Mon, 6 Feb 2012 19:54:48 +0100 Subject: [PATCH 2/3] Following Nick's suggestion, rename posix.fdlistdir() to posix.flistdir(), to be consistent with other functions accepting file descriptors (fdlistdir() was added in 3.3, so hasn't been released yet). --- Doc/library/os.rst | 2 +- Doc/whatsnew/3.3.rst | 2 +- Lib/os.py | 2 +- Lib/test/test_os.py | 4 ++-- Lib/test/test_posix.py | 8 ++++---- Misc/NEWS | 2 +- Modules/posixmodule.c | 10 +++++----- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 8601687227f..06f1452f665 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -769,7 +769,7 @@ as internal buffering of data. .. versionadded:: 3.3 -.. function:: fdlistdir(fd) +.. function:: flistdir(fd) Like :func:`listdir`, but uses a file descriptor instead and always returns strings. diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index c20c889550b..d3044b3f99a 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -571,7 +571,7 @@ os * Other new functions: - * :func:`~os.fdlistdir` (:issue:`10755`) + * :func:`~os.flistdir` (:issue:`10755`) * :func:`~os.getgrouplist` (:issue:`9344`) diff --git a/Lib/os.py b/Lib/os.py index ad5d5381c04..301870cb487 100644 --- a/Lib/os.py +++ b/Lib/os.py @@ -357,7 +357,7 @@ def _fwalk(topfd, toppath, topdown, onerror, followlinks): # whether to follow symlinks flag = 0 if followlinks else AT_SYMLINK_NOFOLLOW - names = fdlistdir(topfd) + names = flistdir(topfd) dirs, nondirs = [], [] for name in names: # Here, we don't use AT_SYMLINK_NOFOLLOW to be consistent with diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 7f955d1e90f..8b07c773468 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -611,8 +611,8 @@ def test_dir_fd(self): for root, dirs, files, rootfd in os.fwalk(*args): # check that the FD is valid os.fstat(rootfd) - # check that fdlistdir() returns consistent information - self.assertEqual(set(os.fdlistdir(rootfd)), set(dirs) | set(files)) + # check that flistdir() returns consistent information + self.assertEqual(set(os.flistdir(rootfd)), set(dirs) | set(files)) def test_fd_leak(self): # Since we're opening a lot of FDs, we must be careful to avoid leaks: diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index f8c6baa0830..c3dfffb1784 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -451,18 +451,18 @@ def test_listdir_default(self): if hasattr(posix, 'listdir'): self.assertTrue(support.TESTFN in posix.listdir()) - @unittest.skipUnless(hasattr(posix, 'fdlistdir'), "test needs posix.fdlistdir()") - def test_fdlistdir(self): + @unittest.skipUnless(hasattr(posix, 'flistdir'), "test needs posix.flistdir()") + def test_flistdir(self): f = posix.open(posix.getcwd(), posix.O_RDONLY) self.addCleanup(posix.close, f) self.assertEqual( sorted(posix.listdir('.')), - sorted(posix.fdlistdir(f)) + sorted(posix.flistdir(f)) ) # Check that the fd offset was reset (issue #13739) self.assertEqual( sorted(posix.listdir('.')), - sorted(posix.fdlistdir(f)) + sorted(posix.flistdir(f)) ) def test_access(self): diff --git a/Misc/NEWS b/Misc/NEWS index 84b16d3e0fc..32ed577ef4e 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1745,7 +1745,7 @@ Library - Issue #11297: Add collections.ChainMap(). -- Issue #10755: Add the posix.fdlistdir() function. Patch by Ross Lagerwall. +- Issue #10755: Add the posix.flistdir() function. Patch by Ross Lagerwall. - Issue #4761: Add the *at() family of functions (openat(), etc.) to the posix module. Patch by Ross Lagerwall. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 2269fe90218..2251a626d6b 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -2867,12 +2867,12 @@ posix_listdir(PyObject *self, PyObject *args) } /* end of posix_listdir */ #ifdef HAVE_FDOPENDIR -PyDoc_STRVAR(posix_fdlistdir__doc__, -"fdlistdir(fd) -> list_of_strings\n\n\ +PyDoc_STRVAR(posix_flistdir__doc__, +"flistdir(fd) -> list_of_strings\n\n\ Like listdir(), but uses a file descriptor instead."); static PyObject * -posix_fdlistdir(PyObject *self, PyObject *args) +posix_flistdir(PyObject *self, PyObject *args) { PyObject *d, *v; DIR *dirp; @@ -2880,7 +2880,7 @@ posix_fdlistdir(PyObject *self, PyObject *args) int fd; errno = 0; - if (!PyArg_ParseTuple(args, "i:fdlistdir", &fd)) + if (!PyArg_ParseTuple(args, "i:flistdir", &fd)) return NULL; /* closedir() closes the FD, so we duplicate it */ fd = dup(fd); @@ -10555,7 +10555,7 @@ static PyMethodDef posix_methods[] = { #endif /* HAVE_LINK */ {"listdir", posix_listdir, METH_VARARGS, posix_listdir__doc__}, #ifdef HAVE_FDOPENDIR - {"fdlistdir", posix_fdlistdir, METH_VARARGS, posix_fdlistdir__doc__}, + {"flistdir", posix_flistdir, METH_VARARGS, posix_flistdir__doc__}, #endif {"lstat", posix_lstat, METH_VARARGS, posix_lstat__doc__}, {"mkdir", posix_mkdir, METH_VARARGS, posix_mkdir__doc__}, From 4a84f58143ca01db181f28df06ac922fbf73a1d7 Mon Sep 17 00:00:00 2001 From: Petri Lehtinen Date: Mon, 9 May 2011 12:24:09 +0200 Subject: [PATCH 3/3] Issue #10811: Fix recursive usage of cursors. Instead of crashing, raise a ProgrammingError now. --- Lib/sqlite3/test/regression.py | 22 ++++++++++++++++++++++ Misc/NEWS | 3 +++ Modules/_sqlite/cursor.c | 29 +++++++++++++++++++---------- Modules/_sqlite/cursor.h | 1 + 4 files changed, 45 insertions(+), 10 deletions(-) diff --git a/Lib/sqlite3/test/regression.py b/Lib/sqlite3/test/regression.py index 7d0553d8f1f..c7551e35a1b 100644 --- a/Lib/sqlite3/test/regression.py +++ b/Lib/sqlite3/test/regression.py @@ -281,6 +281,28 @@ def collation_cb(a, b): # Lone surrogate cannot be encoded to the default encoding (utf8) "\uDC80", collation_cb) + def CheckRecursiveCursorUse(self): + """ + http://bugs.python.org/issue10811 + + Recursively using a cursor, such as when reusing it from a generator led to segfaults. + Now we catch recursive cursor usage and raise a ProgrammingError. + """ + con = sqlite.connect(":memory:") + + cur = con.cursor() + cur.execute("create table a (bar)") + cur.execute("create table b (baz)") + + def foo(): + cur.execute("insert into a (bar) values (?)", (1,)) + yield 1 + + with self.assertRaises(sqlite.ProgrammingError): + cur.executemany("insert into b (baz) values (?)", + ((i,) for i in foo())) + + def suite(): regression_suite = unittest.makeSuite(RegressionTests, "Check") return unittest.TestSuite((regression_suite,)) diff --git a/Misc/NEWS b/Misc/NEWS index 5761ed0a1bc..4a38b148a0d 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -113,6 +113,9 @@ Core and Builtins Library ------- +- Issue #10811: Fix recursive usage of cursors. Instead of crashing, + raise a ProgrammingError now. + - Issue #10881: Fix test_site failure with OS X framework builds. - Issue #964437 Make IDLE help window non-modal. diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c index 763322ff1b6..86fbd4ee0d2 100644 --- a/Modules/_sqlite/cursor.c +++ b/Modules/_sqlite/cursor.c @@ -433,9 +433,14 @@ static int check_cursor(pysqlite_Cursor* cur) if (cur->closed) { PyErr_SetString(pysqlite_ProgrammingError, "Cannot operate on a closed cursor."); return 0; - } else { - return pysqlite_check_thread(cur->connection) && pysqlite_check_connection(cur->connection); } + + if (cur->locked) { + PyErr_SetString(pysqlite_ProgrammingError, "Recursive use of cursors not allowed."); + return 0; + } + + return pysqlite_check_thread(cur->connection) && pysqlite_check_connection(cur->connection); } PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* args) @@ -458,9 +463,10 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* int allow_8bit_chars; if (!check_cursor(self)) { - return NULL; + goto error; } + self->locked = 1; self->reset = 0; /* Make shooting yourself in the foot with not utf-8 decodable 8-bit-strings harder */ @@ -473,12 +479,12 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* if (multiple) { /* executemany() */ if (!PyArg_ParseTuple(args, "OO", &operation, &second_argument)) { - return NULL; + goto error; } if (!PyUnicode_Check(operation)) { PyErr_SetString(PyExc_ValueError, "operation parameter must be str"); - return NULL; + goto error; } if (PyIter_Check(second_argument)) { @@ -489,23 +495,23 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* /* sequence */ parameters_iter = PyObject_GetIter(second_argument); if (!parameters_iter) { - return NULL; + goto error; } } } else { /* execute() */ if (!PyArg_ParseTuple(args, "O|O", &operation, &second_argument)) { - return NULL; + goto error; } if (!PyUnicode_Check(operation)) { PyErr_SetString(PyExc_ValueError, "operation parameter must be str"); - return NULL; + goto error; } parameters_list = PyList_New(0); if (!parameters_list) { - return NULL; + goto error; } if (second_argument == NULL) { @@ -745,7 +751,8 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* * ROLLBACK could have happened */ #ifdef SQLITE_VERSION_NUMBER #if SQLITE_VERSION_NUMBER >= 3002002 - self->connection->inTransaction = !sqlite3_get_autocommit(self->connection->db); + if (self->connection && self->connection->db) + self->connection->inTransaction = !sqlite3_get_autocommit(self->connection->db); #endif #endif @@ -753,6 +760,8 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* Py_XDECREF(parameters_iter); Py_XDECREF(parameters_list); + self->locked = 0; + if (PyErr_Occurred()) { self->rowcount = -1L; return NULL; diff --git a/Modules/_sqlite/cursor.h b/Modules/_sqlite/cursor.h index 5d8b5c160d5..118ba388a41 100644 --- a/Modules/_sqlite/cursor.h +++ b/Modules/_sqlite/cursor.h @@ -42,6 +42,7 @@ typedef struct pysqlite_Statement* statement; int closed; int reset; + int locked; int initialized; /* the next row to be returned, NULL if no next row available */