1. memory leak: ob_refcnt of PyTupleObject is 1 too high

    Report

    1
    static int
    _mysql_ResultObject_Initialize(
    _mysql_ResultObject *self,
    PyObject *args,
    PyObject *kwargs)
    {
    static char *kwlist[] = {"connection", "use", "converter", NULL};
    MYSQL_RES *result;
    _mysql_ConnectionObject *conn=NULL;
    int use=0;
    PyObject *conv=NULL;
    int n, i;
    MYSQL_FIELD *fields;
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iO", kwlist,
    &conn, &use, &conv))
    return -1;
    if (!conv) {
    if (!(conv = PyDict_New()))
    return -1;
    }
    else
    Py_INCREF(conv);
    self->conn = (PyObject *) conn;
    Py_INCREF(conn);
    self->use = use;
    Py_BEGIN_ALLOW_THREADS ;
    if (use)
    result = mysql_use_result(&(conn->connection));
    else
    result = mysql_store_result(&(conn->connection));
    self->result = result;
    Py_END_ALLOW_THREADS ;
    if (!result) {
    if (mysql_field_count(&(conn->connection)) > 0) {
    _mysql_Exception(conn);
    return -1;
    }
    self->converter = PyTuple_New(0);
    Py_DECREF(conv);
    return 0;
    }
    n = mysql_num_fields(result);
    self->nfields = n;
    if (!(self->converter = PyTuple_New(n))) {
    Py_DECREF(conv);
    return -1;
    }
    fields = mysql_fetch_fields(result);
    for (i=0; i<n; i++) {
    PyObject *tmp, *fun;
    tmp = PyInt_FromLong((long) fields[i].type);
    if (!tmp) {
    Py_DECREF(conv);
    return -1;
    }
    fun = PyObject_GetItem(conv, tmp);
    Py_DECREF(tmp);
    if (!fun) {
    if (PyErr_Occurred()) {
    if (!PyErr_ExceptionMatches(PyExc_KeyError)) {
    Py_DECREF(conv);
    return -1;
    }
    PyErr_Clear();
    }
    fun = Py_None;
    Py_INCREF(Py_None);
    }
    else if (PySequence_Check(fun)) {
    int j, n2=PySequence_Size(fun);
    PyObject *fun2=NULL;
    for (j=0; j<n2; j++) {
    PyObject *t = PySequence_GetItem(fun, j);
    if (!t) {
    Py_DECREF(fun);
    Py_DECREF(conv);
    return -1;
    }
    if (PyTuple_Check(t) && PyTuple_GET_SIZE(t) == 2) {
    long mask, flags;
    PyObject *pmask=NULL;
    pmask = PyTuple_GET_ITEM(t, 0);
    fun2 = PyTuple_GET_ITEM(t, 1);
    Py_XINCREF(fun2);
    if (PyInt_Check(pmask)) {
    mask = PyInt_AS_LONG(pmask);
    flags = fields[i].flags;
    if (fields[i].charsetnr != 63) { /* maaagic */
    flags &= ~BINARY_FLAG;
    }
    if (mask & flags) {
    Py_DECREF(t);
    break;
    }
    else {
    fun2 = NULL;
    }
    } else {
    Py_DECREF(t);
    break;
    }
    }
    Py_DECREF(t);
    }
    if (!fun2) {
    fun2 = Py_None;
    Py_INCREF(fun2);
    }
    Py_DECREF(fun);
    fun = fun2;
    }
    PyTuple_SET_ITEM(self->converter, i, fun);
    }
    Py_DECREF(conv);
    return 0;
    }
    1. was expecting final owned ob_refcnt of PyTupleObject to be 0 since nothing references it but final ob_refcnt is refs: 1 owned

      found 50 similar trace(s) to this

    2. when PyArg_ParseTupleAndKeywords() succeeds

      taking False path

    3. taking False path

    4. releasing the GIL by calling PyEval_SaveThread()

    5. when considering range: -0x80000000 <= value <= -1

      taking True path

    6. reacquiring the GIL by calling PyEval_RestoreThread()

    7. when treating unknown struct MYSQL_RES * from _mysql.c:411 as non-NULL

      taking False path

    8. when PyTuple_New() succeeds

      taking False path

      PyTupleObject was allocated at: if (!(self->converter = PyTuple_New(n))) {

    9. when considering range: 1 <= n <= 0xffffffff

      taking True path

    10. when treating unknown struct MYSQL_FIELD * from _mysql.c:434 as non-NULL

      when PyInt_FromLong() succeeds

    11. taking False path

    12. when PyObject_GetItem() succeeds

    13. when taking True path

    14. taking False path

    15. when considering range: -0x80000000 <= value <= -1

      taking True path

    16. when PySequence_Size() succeeds

    17. when considering range: 1 <= n2 <= 0x7fffffff

      taking True path

    18. when PySequence_GetItem() succeeds

    19. taking False path

    20. when considering range: 1 <= value <= 0x4000000

      taking True path

      when considering value == (Py_ssize_t)2 from _mysql.c:462

      taking True path

    21. when treating unknown struct PyObject * from _mysql.c:466 as non-NULL

      taking False path

    22. when treating unknown struct PyObject * from _mysql.c:465 as non-NULL

      when treating unknown struct _typeobject * from _mysql.c:468 as non-NULL

      when considering range: 1 <= value <= 0x800000

      taking True path

    23. when treating unknown struct MYSQL_FIELD * from _mysql.c:470 as non-NULL

    24. when treating unknown struct MYSQL_FIELD * from _mysql.c:471 as non-NULL

      when considering range: 0 <= value <= 62

      taking True path

    25. when considering value == (long int)0 from _mysql.c:474

      taking False path

    26. when taking True path

    27. when considering n2 == (int)1 from _mysql.c:453

      taking False path

    28. taking True path

    29. when taking True path

    30. when considering n == (unsigned int)1 from _mysql.c:425

      taking False path

    31. when considering range: -0x8000000000000000 <= value <= -1

      taking True path