diff -r 10a73648c92c Doc/library/sqlite3.rst --- a/Doc/library/sqlite3.rst Thu Aug 25 20:05:30 2016 -0400 +++ b/Doc/library/sqlite3.rst Fri Aug 26 14:12:15 2016 +0800 @@ -285,9 +285,9 @@ .. versionadded:: 3.2 - .. method:: cursor([cursorClass]) + .. method:: cursor(factory=sqlite3.Cursor) - The cursor method accepts a single optional parameter *cursorClass*. If + The cursor method accepts a single keyword parameter *factory*. If supplied, this must be a custom cursor class that extends :class:`sqlite3.Cursor`. diff -r 10a73648c92c Lib/sqlite3/test/factory.py --- a/Lib/sqlite3/test/factory.py Thu Aug 25 20:05:30 2016 -0400 +++ b/Lib/sqlite3/test/factory.py Fri Aug 26 14:12:15 2016 +0800 @@ -60,6 +60,11 @@ def CheckIsInstance(self): cur = self.con.cursor(factory=MyCursor) self.assertIsInstance(cur, MyCursor) + cur = self.con.cursor() + self.assertIsInstance(cur, sqlite.Cursor) + + def CheckInvalidFactory(self): + self.assertRaises(TypeError, self.con.cursor, 'abcdef') class RowFactoryTestsBackwardsCompat(unittest.TestCase): def setUp(self): @@ -185,7 +190,7 @@ # segmentation fault. class FakeCursor(str): __class__ = sqlite.Cursor - cur = self.con.cursor(factory=FakeCursor) + cur = FakeCursor() self.assertRaises(TypeError, sqlite.Row, cur, ()) def tearDown(self): diff -r 10a73648c92c Lib/sqlite3/test/regression.py --- a/Lib/sqlite3/test/regression.py Thu Aug 25 20:05:30 2016 -0400 +++ b/Lib/sqlite3/test/regression.py Fri Aug 26 14:12:15 2016 +0800 @@ -152,6 +152,18 @@ con = sqlite.connect(":memory:") setattr(con, "isolation_level", "\xe9") + def CheckSetIsolationLevelSegmentationFault(self): + """ + See issue 27861. + """ + class SubStr(str): + def __del__(self): + con.isolation_level = "" + + con = sqlite.connect(":memory:") + con.isolation_level = SubStr("") + con.isolation_level = "" + def CheckCursorConstructorCallCheck(self): """ Verifies that cursor methods check whether base class __init__ was diff -r 10a73648c92c Modules/_sqlite/connection.c --- a/Modules/_sqlite/connection.c Thu Aug 25 20:05:30 2016 -0400 +++ b/Modules/_sqlite/connection.c Fri Aug 26 14:12:15 2016 +0800 @@ -300,7 +300,7 @@ PyObject* pysqlite_connection_cursor(pysqlite_Connection* self, PyObject* args, PyObject* kwargs) { - static char *kwlist[] = {"factory", NULL, NULL}; + static char *kwlist[] = {"factory", NULL}; PyObject* factory = NULL; PyObject* cursor; @@ -309,6 +309,15 @@ return NULL; } + if (factory && + _PyObject_RealIsSubclass(factory, + (PyObject *)&pysqlite_CursorType) <= 0) { + PyErr_Format(PyExc_TypeError, + "factory must be %s", + pysqlite_CursorType.tp_name); + return NULL; + } + if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { return NULL; } @@ -1171,7 +1180,7 @@ PyObject* begin_statement; static PyObject* begin_word; - Py_XDECREF(self->isolation_level); + Py_CLEAR(self->isolation_level); if (self->begin_statement) { PyMem_Free(self->begin_statement);