]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-45126: Fix ref. leak in `sqlite3.Connection.__init__` (GH-28231)
authorErlend Egeberg Aasland <erlend.aasland@innova.no>
Sun, 12 Sep 2021 12:27:42 +0000 (14:27 +0200)
committerGitHub <noreply@github.com>
Sun, 12 Sep 2021 12:27:42 +0000 (21:27 +0900)
Modules/_sqlite/clinic/connection.c.h
Modules/_sqlite/connection.c

index 315d163dde668f916fc660db0bfa961475c4c6b6..bf5a58d7756c9ebb0c68abd196b85ff83a50f49f 100644 (file)
@@ -4,7 +4,7 @@ preserve
 
 static int
 pysqlite_connection_init_impl(pysqlite_Connection *self,
-                              PyObject *database_obj, double timeout,
+                              const char *database, double timeout,
                               int detect_types, PyObject *isolation_level,
                               int check_same_thread, PyObject *factory,
                               int cached_statements, int uri);
@@ -19,7 +19,7 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs)
     PyObject * const *fastargs;
     Py_ssize_t nargs = PyTuple_GET_SIZE(args);
     Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 1;
-    PyObject *database_obj;
+    const char *database = NULL;
     double timeout = 5.0;
     int detect_types = 0;
     PyObject *isolation_level = NULL;
@@ -32,7 +32,7 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs)
     if (!fastargs) {
         goto exit;
     }
-    if (!PyUnicode_FSConverter(fastargs[0], &database_obj)) {
+    if (!clinic_fsconverter(fastargs[0], &database)) {
         goto exit;
     }
     if (!noptargs) {
@@ -97,9 +97,12 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs)
         goto exit;
     }
 skip_optional_pos:
-    return_value = pysqlite_connection_init_impl((pysqlite_Connection *)self, database_obj, timeout, detect_types, isolation_level, check_same_thread, factory, cached_statements, uri);
+    return_value = pysqlite_connection_init_impl((pysqlite_Connection *)self, database, timeout, detect_types, isolation_level, check_same_thread, factory, cached_statements, uri);
 
 exit:
+    /* Cleanup for database */
+    PyMem_Free((void *)database);
+
     return return_value;
 }
 
@@ -816,4 +819,4 @@ exit:
 #ifndef PYSQLITE_CONNECTION_LOAD_EXTENSION_METHODDEF
     #define PYSQLITE_CONNECTION_LOAD_EXTENSION_METHODDEF
 #endif /* !defined(PYSQLITE_CONNECTION_LOAD_EXTENSION_METHODDEF) */
-/*[clinic end generated code: output=9c0dfc6c1ebf9039 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=5b7268875f33c016 input=a9049054013a1b77]*/
index bf803370c0571988f140c77d7ae8275602388c41..3b9e42740d4329bf8b0b3012d3a03c6ed4f2b67f 100644 (file)
 #define HAVE_TRACE_V2
 #endif
 
+static int
+clinic_fsconverter(PyObject *pathlike, const char **result)
+{
+    PyObject *bytes = NULL;
+    Py_ssize_t len;
+    char *str;
+
+    if (!PyUnicode_FSConverter(pathlike, &bytes)) {
+        goto error;
+    }
+    if (PyBytes_AsStringAndSize(bytes, &str, &len) < 0) {
+        goto error;
+    }
+    if ((*result = (const char *)PyMem_Malloc(len+1)) == NULL) {
+        goto error;
+    }
+
+    memcpy((void *)(*result), str, len+1);
+    Py_DECREF(bytes);
+    return 1;
+
+error:
+    Py_XDECREF(bytes);
+    return 0;
+}
+
 #define clinic_state() (pysqlite_get_state(NULL))
 #include "clinic/connection.c.h"
 #undef clinic_state
@@ -81,10 +107,21 @@ new_statement_cache(pysqlite_Connection *self, int maxsize)
     return res;
 }
 
+/*[python input]
+class FSConverter_converter(CConverter):
+    type = "const char *"
+    converter = "clinic_fsconverter"
+    def converter_init(self):
+        self.c_default = "NULL"
+    def cleanup(self):
+        return f"PyMem_Free((void *){self.name});\n"
+[python start generated code]*/
+/*[python end generated code: output=da39a3ee5e6b4b0d input=7b3be538bc4058c0]*/
+
 /*[clinic input]
 _sqlite3.Connection.__init__ as pysqlite_connection_init
 
-    database as database_obj: object(converter='PyUnicode_FSConverter')
+    database: FSConverter
     timeout: double = 5.0
     detect_types: int = 0
     isolation_level: object = NULL
@@ -96,23 +133,21 @@ _sqlite3.Connection.__init__ as pysqlite_connection_init
 
 static int
 pysqlite_connection_init_impl(pysqlite_Connection *self,
-                              PyObject *database_obj, double timeout,
+                              const char *database, double timeout,
                               int detect_types, PyObject *isolation_level,
                               int check_same_thread, PyObject *factory,
                               int cached_statements, int uri)
-/*[clinic end generated code: output=dc19df1c0e2b7b77 input=aa1f21bf12fe907a]*/
+/*[clinic end generated code: output=bc39e55eb0b68783 input=f8d1f7efc0d84104]*/
 {
     int rc;
 
-    if (PySys_Audit("sqlite3.connect", "O", database_obj) < 0) {
+    if (PySys_Audit("sqlite3.connect", "s", database) < 0) {
         return -1;
     }
 
     pysqlite_state *state = pysqlite_get_state_by_type(Py_TYPE(self));
     self->state = state;
 
-    const char *database = PyBytes_AsString(database_obj);
-
     self->begin_statement = NULL;
 
     Py_CLEAR(self->statement_cache);
@@ -130,8 +165,6 @@ pysqlite_connection_init_impl(pysqlite_Connection *self,
                          (uri ? SQLITE_OPEN_URI : 0), NULL);
     Py_END_ALLOW_THREADS
 
-    Py_DECREF(database_obj);  // needed bco. the AC FSConverter
-
     if (rc != SQLITE_OK) {
         _pysqlite_seterror(state, self->db);
         return -1;