Changeset 655 for trunk


Ignore:
Timestamp:
Nov 28, 2015, 7:32:31 AM (4 years ago)
Author:
cito
Message:

Fix garbage collection issues

This patch fixes memory management problems, particularly on Windows.

The query() method and the handling of object references inside the method has
been greatly simplified and corrected. Note that we don't calculate and pass
the paramLengths any more since this is only needed when also passing info about
binary data in paramFormats. We also use PyMem_Malloc() instead of malloc() to
allocate memory to make sure the memory is allocated in the Python heap.

Location:
trunk/module
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/module/pgmodule.c

    r652 r655  
    253253        int j;
    254254
    255         if (!(typ = malloc(sizeof(int) * nfields)))
     255        if (!(typ = PyMem_Malloc(sizeof(int) * nfields)))
    256256        {
    257257                PyErr_SetString(PyExc_MemoryError, "memory error in getresult().");
     
    389389        if (n > 0)
    390390        {
    391                 char * const aligns = (char *) malloc(n * sizeof(char));
    392                 int * const sizes = (int *) malloc(n * sizeof(int));
     391                char * const aligns = (char *) PyMem_Malloc(n * sizeof(char));
     392                int * const sizes = (int *) PyMem_Malloc(n * sizeof(int));
    393393
    394394                if (aligns && sizes)
     
    458458                        size += 40;
    459459                        /* is the buffer size that needs to be allocated */
    460                         buffer = (char *) malloc(size);
     460                        buffer = (char *) PyMem_Malloc(size);
    461461                        if (buffer)
    462462                        {
     
    515515                                }
    516516                                /* free memory */
    517                                 free(aligns);
    518                                 free(sizes);
     517                                PyMem_Free(aligns);
     518                                PyMem_Free(sizes);
    519519                                /* create the footer */
    520520                                sprintf(p, "(%d row%s)", m, m == 1 ? "" : "s");
    521521                                /* return the result */
    522522                                result = PyStr_FromString(buffer);
    523                                 free(buffer);
     523                                PyMem_Free(buffer);
    524524                                return result;
    525525                        }
     
    531531                        }
    532532                } else {
    533                         if (aligns)
    534                                 free(aligns);
    535                         if (sizes)
    536                                 free(aligns);
     533                        PyMem_Free(aligns);
     534                        PyMem_Free(sizes);
    537535                        PyErr_SetString(PyExc_MemoryError,
    538536                                "Not enough memory for formatting the query result.");
     
    11201118{
    11211119        PyObject        *query_obj;
    1122         PyObject        *oargs = NULL;
    1123         char            *query = NULL;
     1120        PyObject        *param_obj = NULL;
     1121        char            *query;
    11241122        PGresult        *result;
    11251123        queryObject *npgobj;
     
    11351133
    11361134        /* get query args */
    1137         if (!PyArg_ParseTuple(args, "O|O", &query_obj, &oargs))
     1135        if (!PyArg_ParseTuple(args, "O|O", &query_obj, &param_obj))
    11381136        {
    11391137                return NULL;
     
    11451143        {
    11461144                query = PyBytes_AsString(query_obj);
     1145                query_obj = NULL;
    11471146        }
    11481147        else if (PyUnicode_Check(query_obj))
     
    11521151                query = PyBytes_AsString(query_obj);
    11531152        }
    1154         if (!query)
     1153        else
    11551154        {
    11561155                PyErr_SetString(PyExc_TypeError,
     
    11591158        }
    11601159
    1161         /* If oargs is passed, ensure it's a non-empty tuple. We want to treat
     1160        /* If param_obj is passed, ensure it's a non-empty tuple. We want to treat
    11621161         * an empty tuple the same as no argument since we'll get that when the
    11631162         * caller passes no arguments to db.query(), and historic behaviour was
    11641163         * to call PQexec() in that case, which can execute multiple commands. */
    1165         if (oargs)
    1166         {
    1167                 if (!PyTuple_Check(oargs) && !PyList_Check(oargs))
     1164        if (param_obj)
     1165        {
     1166                param_obj = PySequence_Fast(param_obj,
     1167                        "query parameters must be a sequence.");
     1168                if (!param_obj)
    11681169                {
    1169                         PyErr_SetString(PyExc_TypeError,
    1170                                 "query parameters must be a tuple or list.");
     1170                        Py_XDECREF(query_obj);
    11711171                        return NULL;
    11721172                }
    1173 
    1174                 nparms = (int)PySequence_Size(oargs);
     1173                nparms = (int)PySequence_Fast_GET_SIZE(param_obj);
     1174
     1175                /* if there's a single argument and it's a list or tuple, it
     1176                 * contains the positional arguments. */
     1177                if (nparms == 1)
     1178                {
     1179                        PyObject *first_obj = PySequence_Fast_GET_ITEM(param_obj, 0);
     1180                        if (PyList_Check(first_obj) || PyTuple_Check(first_obj))
     1181                        {
     1182                                Py_DECREF(param_obj);
     1183                                param_obj = PySequence_Fast(first_obj, NULL);
     1184                                nparms = (int)PySequence_Fast_GET_SIZE(param_obj);
     1185                        }
     1186                }
    11751187        }
    11761188
     
    11791191        {
    11801192                /* prepare arguments */
    1181                 PyObject        **str, **s, *obj = PySequence_GetItem(oargs, 0);
     1193                PyObject        **str, **s;
    11821194                char            **parms, **p;
    1183                 int                     *lparms, *l;
    11841195                register int i;
    11851196
    1186                 /* if there's a single argument and it's a list or tuple, it
    1187                  * contains the positional aguments. */
    1188                 if (nparms == 1 && (PyList_Check(obj) || PyTuple_Check(obj)))
    1189                 {
    1190                         oargs = obj;
    1191                         nparms = (int)PySequence_Size(oargs);
     1197                str = (PyObject **)PyMem_Malloc(nparms * sizeof(*str));
     1198                parms = (char **)PyMem_Malloc(nparms * sizeof(*parms));
     1199                if (!str || !parms) {
     1200                        PyMem_Free(parms);
     1201                        PyMem_Free(str);
     1202                        Py_XDECREF(query_obj);
     1203                        Py_XDECREF(param_obj);
     1204                        PyErr_SetString(PyExc_MemoryError, "memory error in query().");
     1205                        return NULL;
    11921206                }
    1193                 str = (PyObject **)malloc(nparms * sizeof(*str));
    1194                 parms = (char **)malloc(nparms * sizeof(*parms));
    1195                 lparms = (int *)malloc(nparms * sizeof(*lparms));
    11961207
    11971208                /* convert optional args to a list of strings -- this allows
    11981209                 * the caller to pass whatever they like, and prevents us
    11991210                 * from having to map types to OIDs */
    1200                 for (i = 0, s=str, p=parms, l=lparms; i < nparms; i++, s++, p++, l++)
     1211                for (i = 0, s=str, p=parms; i < nparms; i++, p++)
    12011212                {
    1202                         obj = PySequence_GetItem(oargs, i);
     1213                        PyObject *obj = PySequence_Fast_GET_ITEM(param_obj, i);
    12031214
    12041215                        if (obj == Py_None)
    12051216                        {
    1206                                 *s = NULL;
    12071217                                *p = NULL;
    1208                                 *l = 0;
    12091218                        }
    12101219                        else if (PyBytes_Check(obj))
    12111220                        {
    1212                                 PyBytes_AsStringAndSize(*s = obj, p, (Py_ssize_t *)l);
     1221                                *p = PyBytes_AsString(obj);
    12131222                        }
    12141223                        else if (PyUnicode_Check(obj))
    12151224                        {
    1216                                 *s = get_encoded_string(obj, encoding);
    1217                                 if (!*s)
     1225                                PyObject *str_obj = get_encoded_string(obj, encoding);
     1226                                if (!str_obj)
    12181227                                {
    1219                                         free(lparms); free(parms);
    1220                                         while (i--)
    1221                                         {
    1222                                                 if (*--s)
    1223                                                 {
    1224                                                         Py_DECREF(*s);
    1225                                                 }
    1226                                         }
    1227                                         free(str);
     1228                                        PyMem_Free(parms);
     1229                                        while (s != str) { s--; Py_DECREF(*s); }
     1230                                        PyMem_Free(str);
     1231                                        Py_XDECREF(query_obj);
     1232                                        Py_XDECREF(param_obj);
    12281233                                        /* pass the UnicodeEncodeError */
    12291234                                        return NULL;
    12301235                                }
    1231                                 PyBytes_AsStringAndSize(*s, p, (Py_ssize_t *)l);
     1236                                *s++ = str_obj;
     1237                                *p = PyBytes_AsString(str_obj);
    12321238                        }
    12331239                        else
    12341240                        {
    1235                                 *s = PyObject_Str(obj);
    1236                                 if (!*s)
     1241                                PyObject *str_obj = PyObject_Str(obj);
     1242                                if (!str_obj)
    12371243                                {
    1238                                         free(lparms); free(parms);
    1239                                         while (i--)
    1240                                         {
    1241                                                 if (*--s)
    1242                                                 {
    1243                                                         Py_DECREF(*s);
    1244                                                 }
    1245                                         }
    1246                                         free(str);
     1244                                        PyMem_Free(parms);
     1245                                        while (s != str) { s--; Py_DECREF(*s); }
     1246                                        PyMem_Free(str);
     1247                                        Py_XDECREF(query_obj);
     1248                                        Py_XDECREF(param_obj);
    12471249                                        PyErr_SetString(PyExc_TypeError,
    12481250                                                "query parameter has no string representation");
    12491251                                        return NULL;
    12501252                                }
    1251                                 *p = PyStr_AsString(*s);
    1252                                 *l = (int)strlen(*p);
     1253                                *s++ = str_obj;
     1254                                *p = PyStr_AsString(str_obj);
    12531255                        }
    12541256                }
     
    12561258                Py_BEGIN_ALLOW_THREADS
    12571259                result = PQexecParams(self->cnx, query, nparms,
    1258                         NULL, (const char * const *)parms, lparms, NULL, 0);
     1260                        NULL, (const char * const *)parms, NULL, NULL, 0);
    12591261                Py_END_ALLOW_THREADS
    12601262
    1261                 free(lparms); free(parms);
    1262                 for (i = 0, s=str; i < nparms; i++, s++)
    1263                 {
    1264                         if (*s)
    1265                         {
    1266                                 Py_DECREF(*s);
    1267                         }
    1268                 }
    1269                 free(str);
     1263                PyMem_Free(parms);
     1264                while (s != str) { s--; Py_DECREF(*s); }
     1265                PyMem_Free(str);
    12701266        }
    12711267        else
     
    12751271                Py_END_ALLOW_THREADS
    12761272        }
     1273
     1274        /* we don't need the query and its params any more */
     1275        Py_XDECREF(query_obj);
     1276        Py_XDECREF(param_obj);
    12771277
    12781278        /* checks result validity */
     
    15161516
    15171517        /* allocate buffer */
    1518         if (!(buffer = malloc(MAX_BUFFER_SIZE)))
     1518        if (!(buffer = PyMem_Malloc(MAX_BUFFER_SIZE)))
    15191519        {
    15201520                PyErr_SetString(PyExc_MemoryError,
     
    15321532        if (!result)
    15331533        {
    1534                 free(buffer);
     1534                PyMem_Free(buffer);
    15351535                PyErr_SetString(PyExc_ValueError, PQerrorMessage(self->cnx));
    15361536                return NULL;
     
    15671567                        if (j != n)
    15681568                        {
    1569                                 free(buffer);
     1569                                PyMem_Free(buffer);
    15701570                                PyErr_SetString(PyExc_TypeError,
    15711571                                        "arrays contained in second arg must have same size.");
     
    16201620                                if (!s)
    16211621                                {
    1622                                         free(buffer);
     1622                                        PyMem_Free(buffer);
    16231623                                        return NULL; /* pass the UnicodeEncodeError */
    16241624                                }
     
    16631663                        if (bufsiz <= 0)
    16641664                        {
    1665                                 free(buffer);
     1665                                PyMem_Free(buffer);
    16661666                                PyErr_SetString(PyExc_MemoryError,
    16671667                                        "insert buffer overflow.");
     
    16781678                        PyErr_SetString(PyExc_IOError, PQerrorMessage(self->cnx));
    16791679                        PQendcopy(self->cnx);
    1680                         free(buffer);
     1680                        PyMem_Free(buffer);
    16811681                        return NULL;
    16821682                }
     
    16881688                PyErr_SetString(PyExc_IOError, PQerrorMessage(self->cnx));
    16891689                PQendcopy(self->cnx);
    1690                 free(buffer);
     1690                PyMem_Free(buffer);
    16911691                return NULL;
    16921692        }
     
    16951695        {
    16961696                PyErr_SetString(PyExc_IOError, PQerrorMessage(self->cnx));
    1697                 free(buffer);
    1698                 return NULL;
    1699         }
    1700 
    1701         free(buffer);
     1697                PyMem_Free(buffer);
     1698                return NULL;
     1699        }
     1700
     1701        PyMem_Free(buffer);
    17021702
    17031703        /* no error : returns nothing */
     
    17741774        PyObject   *from_obj, /* the object that was passed in */
    17751775                           *to_obj; /* string object to return */
    1776         char       *from=NULL, /* our string argument as encoded string */
     1776        char       *from, /* our string argument as encoded string */
    17771777                           *to; /* the result as encoded string */
    17781778        Py_ssize_t      from_length; /* length of string */
     
    17861786        {
    17871787                PyBytes_AsStringAndSize(from_obj, &from, &from_length);
     1788                from_obj = NULL;
    17881789        }
    17891790        else if (PyUnicode_Check(from_obj))
     
    17941795                PyBytes_AsStringAndSize(from_obj, &from, &from_length);
    17951796        }
    1796         if (!from)
     1797        else
    17971798        {
    17981799                PyErr_SetString(PyExc_TypeError, "escape_literal() expects a string.");
     
    18021803        to = PQescapeLiteral(self->cnx, from, (size_t)from_length);
    18031804        to_length = strlen(to);
     1805
     1806        Py_XDECREF(from_obj);
    18041807
    18051808        if (encoding == -1)
     
    18211824        PyObject   *from_obj, /* the object that was passed in */
    18221825                           *to_obj; /* string object to return */
    1823         char       *from=NULL, /* our string argument as encoded string */
     1826        char       *from, /* our string argument as encoded string */
    18241827                           *to; /* the result as encoded string */
    18251828        Py_ssize_t      from_length; /* length of string */
     
    18331836        {
    18341837                PyBytes_AsStringAndSize(from_obj, &from, &from_length);
     1838                from_obj = NULL;
    18351839        }
    18361840        else if (PyUnicode_Check(from_obj))
     
    18411845                PyBytes_AsStringAndSize(from_obj, &from, &from_length);
    18421846        }
    1843         if (!from)
     1847        else
    18441848        {
    18451849                PyErr_SetString(PyExc_TypeError,
     
    18501854        to = PQescapeIdentifier(self->cnx, from, (size_t)from_length);
    18511855        to_length = strlen(to);
     1856
     1857        Py_XDECREF(from_obj);
    18521858
    18531859        if (encoding == -1)
     
    18711877        PyObject   *from_obj, /* the object that was passed in */
    18721878                           *to_obj; /* string object to return */
    1873         char       *from=NULL, /* our string argument as encoded string */
     1879        char       *from, /* our string argument as encoded string */
    18741880                           *to; /* the result as encoded string */
    18751881        Py_ssize_t      from_length; /* length of string */
     
    18831889        {
    18841890                PyBytes_AsStringAndSize(from_obj, &from, &from_length);
     1891                from_obj = NULL;
    18851892        }
    18861893        else if (PyUnicode_Check(from_obj))
     
    18911898                PyBytes_AsStringAndSize(from_obj, &from, &from_length);
    18921899        }
    1893         if (!from)
     1900        else
    18941901        {
    18951902                PyErr_SetString(PyExc_TypeError, "escape_string() expects a string.");
     
    19031910                from_length = (from_length - 1)/2;
    19041911        }
    1905         to = (char *)malloc(to_length);
     1912        to = (char *)PyMem_Malloc(to_length);
    19061913        to_length = PQescapeStringConn(self->cnx,
    19071914                to, from, (size_t)from_length, NULL);
     1915
     1916        Py_XDECREF(from_obj);
    19081917
    19091918        if (encoding == -1)
     
    19111920        else
    19121921                to_obj = get_decoded_string(to, to_length, encoding);
    1913         if (to)
    1914                 free(to);
     1922        PyMem_Free(to);
    19151923        return to_obj;
    19161924}
     
    19251933        PyObject   *from_obj, /* the object that was passed in */
    19261934                           *to_obj; /* string object to return */
    1927         char       *from=NULL, /* our string argument as encoded string */
     1935        char       *from, /* our string argument as encoded string */
    19281936                           *to; /* the result as encoded string */
    19291937        Py_ssize_t      from_length; /* length of string */
     
    19371945        {
    19381946                PyBytes_AsStringAndSize(from_obj, &from, &from_length);
     1947                from_obj = NULL;
    19391948        }
    19401949        else if (PyUnicode_Check(from_obj))
     
    19451954                PyBytes_AsStringAndSize(from_obj, &from, &from_length);
    19461955        }
    1947         if (!from)
     1956        else
    19481957        {
    19491958                PyErr_SetString(PyExc_TypeError, "escape_bytea() expects a string.");
     
    19531962        to = (char *)PQescapeByteaConn(self->cnx,
    19541963                (unsigned char *)from, (size_t)from_length, &to_length);
     1964
     1965        Py_XDECREF(from_obj);
    19551966
    19561967        if (encoding == -1)
     
    25432554{
    25442555        PyObject        *query_obj;
    2545         char            *query = NULL;
     2556        char            *query;
    25462557        int                     encoding;
    25472558
     
    25652576        {
    25662577                query = PyBytes_AsString(query_obj);
     2578                query_obj = NULL;
    25672579        }
    25682580        else if (PyUnicode_Check(query_obj))
     
    25722584                query = PyBytes_AsString(query_obj);
    25732585        }
    2574         if (!query)
     2586        else
    25752587        {
    25762588                PyErr_SetString(PyExc_TypeError, "executed sql must be a string.");
     
    25932605        self->result = PQexec(self->pgcnx->cnx, query);
    25942606        Py_END_ALLOW_THREADS
     2607
     2608        /* we don't need the query any more */
     2609        Py_XDECREF(query_obj);
    25952610
    25962611        /* checks result validity */
     
    35303545
    35313546exit:
    3532         free(coltypes);
     3547        PyMem_Free(coltypes);
    35333548
    35343549        /* returns list */
     
    37023717
    37033718exit:
    3704         free(coltypes);
     3719        PyMem_Free(coltypes);
    37053720
    37063721        /* returns list */
     
    39263941        PyObject   *from_obj, /* the object that was passed in */
    39273942                           *to_obj; /* string object to return */
    3928         char       *from=NULL, /* our string argument as encoded string */
     3943        char       *from, /* our string argument as encoded string */
    39293944                           *to; /* the result as encoded string */
    39303945        Py_ssize_t      from_length; /* length of string */
     
    39383953        {
    39393954                PyBytes_AsStringAndSize(from_obj, &from, &from_length);
     3955                from_obj = NULL;
    39403956        }
    39413957        else if (PyUnicode_Check(from_obj))
     
    39463962                PyBytes_AsStringAndSize(from_obj, &from, &from_length);
    39473963        }
    3948         if (!from)
     3964        else
    39493965        {
    39503966                PyErr_SetString(PyExc_TypeError, "escape_string() expects a string.");
     
    39583974                from_length = (from_length - 1)/2;
    39593975        }
    3960         to = (char *)malloc(to_length);
     3976        to = (char *)PyMem_Malloc(to_length);
    39613977        to_length = (int)PQescapeString(to, from, (size_t)from_length);
     3978
     3979        Py_XDECREF(from_obj);
    39623980
    39633981        if (encoding == -1)
     
    39653983        else
    39663984                to_obj = get_decoded_string(to, to_length, encoding);
    3967         if (to)
    3968                 free(to);
     3985        PyMem_Free(to);
    39693986        return to_obj;
    39703987}
     
    39793996        PyObject   *from_obj, /* the object that was passed in */
    39803997                           *to_obj; /* string object to return */
    3981         char       *from=NULL, /* our string argument as encoded string */
     3998        char       *from, /* our string argument as encoded string */
    39823999                           *to; /* the result as encoded string */
    39834000        Py_ssize_t      from_length; /* length of string */
     
    39914008        {
    39924009                PyBytes_AsStringAndSize(from_obj, &from, &from_length);
     4010                from_obj = NULL;
    39934011        }
    39944012        else if (PyUnicode_Check(from_obj))
     
    39994017                PyBytes_AsStringAndSize(from_obj, &from, &from_length);
    40004018        }
    4001         if (!from)
     4019        else
    40024020        {
    40034021                PyErr_SetString(PyExc_TypeError, "escape_bytea() expects a string.");
     
    40074025        to = (char *)PQescapeBytea(
    40084026                (unsigned char*)from, (size_t)from_length, &to_length);
     4027
     4028        Py_XDECREF(from_obj);
    40094029
    40104030        if (encoding == -1)
     
    40264046        PyObject   *from_obj, /* the object that was passed in */
    40274047                           *to_obj; /* string object to return */
    4028         char       *from=NULL, /* our string argument as encoded string */
     4048        char       *from, /* our string argument as encoded string */
    40294049                           *to; /* the result as encoded string */
    40304050        Py_ssize_t      from_length; /* length of string */
     
    40374057        {
    40384058                PyBytes_AsStringAndSize(from_obj, &from, &from_length);
     4059                from_obj = NULL;
    40394060        }
    40404061        else if (PyUnicode_Check(from_obj))
     
    40444065                PyBytes_AsStringAndSize(from_obj, &from, &from_length);
    40454066        }
    4046         if (!from)
     4067        else
    40474068        {
    40484069                PyErr_SetString(PyExc_TypeError, "unescape_bytea() expects a string.");
     
    40514072
    40524073        to = (char *)PQunescapeBytea((unsigned char*)from, &to_length);
     4074
     4075        Py_XDECREF(from_obj);
    40534076
    40544077        to_obj = PyBytes_FromStringAndSize(to, to_length);
  • trunk/module/tests/test_classic_connection.py

    r648 r655  
    717717
    718718    def testQueryWithNoneParam(self):
     719        self.assertRaises(TypeError, self.c.query, "select $1", None)
     720        self.assertRaises(TypeError, self.c.query, "select $1+$2", None, None)
    719721        self.assertEqual(self.c.query("select $1::integer", (None,)
    720722            ).getresult(), [(None,)])
    721723        self.assertEqual(self.c.query("select $1::text", [None]
     724            ).getresult(), [(None,)])
     725        self.assertEqual(self.c.query("select $1::text", [[None]]
    722726            ).getresult(), [(None,)])
    723727
Note: See TracChangeset for help on using the changeset viewer.