1. returning pointer to deallocated memory

    Report

    1
    /* Extracted copy of PylibMC_Client_get_multi */
    static PyObject *PylibMC_Client_get_multi(
    PylibMC_Client *self, PyObject *args, PyObject *kwds) {
    PyObject *key_seq, **key_objs, *retval = NULL;
    char **keys, *prefix = NULL;
    char *err_func = NULL;
    memcached_result_st *res, *results = NULL;
    int prefix_len = 0;
    Py_ssize_t i;
    PyObject *key_it, *ckey;
    size_t *key_lens;
    size_t nkeys, nresults = 0;
    memcached_return rc;
    static char *kws[] = { "keys", "key_prefix", NULL };
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s#:get_multi", kws,
    &key_seq, &prefix, &prefix_len))
    return NULL;
    if ((nkeys = (size_t)PySequence_Length(key_seq)) == -1)
    return NULL;
    /* Populate keys and key_lens. */
    keys = PyMem_New(char *, nkeys);
    key_lens = PyMem_New(size_t, nkeys);
    key_objs = PyMem_New(PyObject *, nkeys);
    if (!keys || !key_lens || !key_objs) {
    PyMem_Free(keys);
    PyMem_Free(key_lens);
    PyMem_Free(key_objs);
    return PyErr_NoMemory();
    }
    /* Clear potential previous exception, because we explicitly check for
    * exceptions as a loop predicate. */
    PyErr_Clear();
    /* Iterate through all keys and set lengths etc. */
    key_it = PyObject_GetIter(key_seq);
    i = 0;
    while ((ckey = PyIter_Next(key_it)) != NULL) {
    char *key;
    Py_ssize_t key_len;
    PyObject *rkey;
    assert(i < nkeys);
    if (PyErr_Occurred() || !_PylibMC_CheckKey(ckey)) {
    nkeys = i;
    goto earlybird;
    }
    PyString_AsStringAndSize(ckey, &key, &key_len);
    key_lens[i] = (size_t)(key_len + prefix_len);
    /* Skip empty keys */
    if (!key_lens[i])
    continue;
    /* determine rkey, the prefixed ckey */
    if (prefix != NULL) {
    rkey = PyString_FromStringAndSize(prefix, prefix_len);
    PyString_Concat(&rkey, ckey);
    if (rkey == NULL)
    goto earlybird;
    rkey = PyString_FromFormat("%s%s",
    prefix, PyString_AS_STRING(ckey));
    } else {
    Py_INCREF(ckey);
    rkey = ckey;
    }
    Py_DECREF(ckey);
    keys[i] = PyString_AS_STRING(rkey);
    key_objs[i++] = rkey;
    }
    nkeys = i;
    Py_XDECREF(key_it);
    if (nkeys == 0) {
    retval = PyDict_New();
    goto earlybird;
    } else if (PyErr_Occurred()) {
    nkeys--;
    goto earlybird;
    }
    /* TODO Make an iterator interface for getting each key separately.
    *
    * This would help large retrievals, as a single dictionary containing all
    * the data at once isn't needed. (Should probably look into if it's even
    * worth it.)
    */
    Py_BEGIN_ALLOW_THREADS;
    rc = pylibmc_memcached_fetch_multi(self->mc,
    keys, nkeys, key_lens,
    &results, &nresults,
    &err_func);
    Py_END_ALLOW_THREADS;
    if (rc != MEMCACHED_SUCCESS) {
    PylibMC_ErrFromMemcached(self, err_func, rc);
    goto earlybird;
    }
    retval = PyDict_New();
    for (i = 0; i < nresults; i++) {
    PyObject *val, *key_obj;
    int rc;
    res = results + i;
    /* Explicitly construct a key string object so that NUL-bytes and the
    * likes can be contained within the keys (this is possible in the
    * binary protocol.) */
    key_obj = PyString_FromStringAndSize(memcached_result_key_value(res) + prefix_len,
    memcached_result_key_length(res) - prefix_len);
    if (key_obj == NULL)
    goto unpack_error;
    /* Parse out value */
    val = _PylibMC_parse_memcached_result(res);
    if (val == NULL)
    goto unpack_error;
    rc = PyDict_SetItem(retval, key_obj, val);
    Py_DECREF(key_obj);
    Py_DECREF(val);
    if (rc != 0)
    goto unpack_error;
    continue;
    unpack_error:
    Py_DECREF(retval);
    break;
    }
    earlybird:
    PyMem_Free(key_lens);
    PyMem_Free(keys);
    for (i = 0; i < nkeys; i++)
    Py_DECREF(key_objs[i]);
    PyMem_Free(key_objs);
    if (results != NULL) {
    for (i = 0; i < nresults && results != NULL; i++) {
    memcached_result_free(results + i);
    }
    PyMem_Free(results);
    }
    /* Not INCREFing because the only two outcomes are NULL and a new dict.
    * We're the owner of that dict already, so. */
    return retval;
    }
    1. when _PyArg_ParseTupleAndKeywords_SizeT() succeeds

      taking False path

    2. when PySequence_Size() succeeds

      taking False path

    3. when considering range: 0 <= value <= 0xfffffffffffffff

      taking True path

      when PyMem_Malloc() succeeds

    4. taking True path

      when PyMem_Malloc() succeeds

    5. taking True path

      when PyMem_Malloc() succeeds

    6. taking False path

      taking False path

      taking False path

    7. calling PyErr_Clear()

    8. when PyObject_GetIter() succeeds

    9. when PyIter_Next() retrieves a value (new ref)

      taking True path

    10. when considering range: 1 <= nkeys <= 0xfffffffffffffff

      taking False path

    11. PyErr_Occurred()

      taking False path

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

      taking False path

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

      taking False path

    13. when treating unknown const char * from libcpychecker/html/test/example2/pylibmc-issue-68.c:68 as non-NULL

      taking True path

    14. when PyString_FromStringAndSize() succeeds

    15. when PyString_Concat() succeeds (Py_DECREF() without deallocation on *LHS)

      taking False path

    16. when PyString_FromFormat() succeeds

    17. when taking True path

    18. when PyIter_Next() returns NULL without setting an exception (end of iteration)

      taking False path

    19. taking False path

      when taking True path

    20. taking False path

    21. PyErr_Occurred()

      taking False path

    22. releasing the GIL by calling PyEval_SaveThread()

    23. reacquiring the GIL by calling PyEval_RestoreThread()

    24. when considering value == (int)0 from libcpychecker/html/test/example2/pylibmc-issue-68.c:148

      taking False path

    25. when PyDict_New() succeeds

    26. when taking True path

    27. when PyString_FromStringAndSize() succeeds

    28. taking False path

    29. when treating unknown struct PyObject * from libcpychecker/html/test/example2/pylibmc-issue-68.c:176 as non-NULL

      taking False path

    30. when PyDict_SetItem() fails

    31. when taking True path

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

      taking True path

    33. taking True path

    34. when taking False path

      calling tp_dealloc on PyDictObject allocated at libcpychecker/html/test/example2/pylibmc-issue-68.c:159

      memory deallocated here

    35. calling PyMem_Free on PyMem_Malloc allocated at libcpychecker/html/test/example2/pylibmc-issue-68.c:77

    36. calling PyMem_Free on PyMem_Malloc allocated at libcpychecker/html/test/example2/pylibmc-issue-68.c:76

    37. taking True path

    38. when taking True path

    39. taking False path

    40. calling PyMem_Free on PyMem_Malloc allocated at libcpychecker/html/test/example2/pylibmc-issue-68.c:78

    41. when treating unknown struct memcached_result_st * * from libcpychecker/html/test/example2/pylibmc-issue-68.c:148 as non-NULL

      taking True path

    42. when taking True path

      taking True path

      when taking False path

    43. calling PyMem_Free on Region('heap-region-12')

    44. found 11 similar trace(s) to this