| /* 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; |
| } |
when _PyArg_ParseTupleAndKeywords_SizeT() succeeds
taking False path
when PySequence_Size() succeeds
taking False path
when considering range: 0 <= value <= 0xfffffffffffffff
taking True path
when PyMem_Malloc() succeeds
taking True path
when PyMem_Malloc() succeeds
taking True path
when PyMem_Malloc() succeeds
taking False path
taking False path
taking False path
calling PyErr_Clear()
when PyObject_GetIter() succeeds
when PyIter_Next() retrieves a value (new ref)
taking True path
when considering range: 1 <= nkeys <= 0xfffffffffffffff
taking False path
PyErr_Occurred()
taking False path
when considering range: -0x80000000 <= value <= -1
taking False path
when considering range: -0x8000000000000000 <= value <= -1
taking False path
when treating unknown const char * from libcpychecker/html/test/example2/pylibmc-issue-68.c:68 as non-NULL
taking True path
when PyString_FromStringAndSize() succeeds
when PyString_Concat() succeeds (Py_DECREF() without deallocation on *LHS)
taking False path
when PyString_FromFormat() succeeds
when taking True path
when PyIter_Next() returns NULL without setting an exception (end of iteration)
taking False path
taking False path
when taking True path
taking False path
PyErr_Occurred()
taking False path
releasing the GIL by calling PyEval_SaveThread()
reacquiring the GIL by calling PyEval_RestoreThread()
when considering value == (int)0 from libcpychecker/html/test/example2/pylibmc-issue-68.c:148
taking False path
when PyDict_New() succeeds
when taking True path
when PyString_FromStringAndSize() succeeds
taking False path
when treating unknown struct PyObject * from libcpychecker/html/test/example2/pylibmc-issue-68.c:176 as non-NULL
taking False path
when PyDict_SetItem() fails
when taking True path
when considering range: -0x8000000000000000 <= value <= -1
taking True path
taking True path
when taking False path
calling tp_dealloc on PyDictObject allocated at libcpychecker/html/test/example2/pylibmc-issue-68.c:159
memory deallocated here
calling PyMem_Free on PyMem_Malloc allocated at libcpychecker/html/test/example2/pylibmc-issue-68.c:77
calling PyMem_Free on PyMem_Malloc allocated at libcpychecker/html/test/example2/pylibmc-issue-68.c:76
taking True path
when taking True path
taking False path
calling PyMem_Free on PyMem_Malloc allocated at libcpychecker/html/test/example2/pylibmc-issue-68.c:78
when treating unknown struct memcached_result_st * * from libcpychecker/html/test/example2/pylibmc-issue-68.c:148 as non-NULL
taking True path
when taking True path
taking True path
when taking False path
calling PyMem_Free on Region('heap-region-12')
found 11 similar trace(s) to this