Search code examples
pythoncpython-3.xpython-c-api

Is incrementing Py_True/Py_False refcount always necessary?


I'm new to the Python C-API and browsing through some source code to pick parts of it up.

Here is a minimal version of a function that I found, in the C source of a package that contains extension modules:

#define PY_SSIZE_T_CLEAN
#include <Python.h>

static PyObject *
modulename_myfunc(PyObject *self, PyObject *args) {

    // Call PyArg_ParseTuple, etc ...

    // Dummy values; in the real function they are calculated
    int is_found = 1;
    Py_ssize_t n_bytes_found = 1024;

    PyObject *result;
    result = Py_BuildValue("(Oi)",
                           is_found ? Py_True : Py_False,  // Py_INCREF?
                           n_bytes_found);
    return result;
}

Does this introduce a small memory leak by failing to use Py_INCREF on either Py_True or Py_False? The C-API docs for Boolean object seem pretty explicit about always needing to incref/decref Py_True and Py_False.

If a Py_INCREF does need to be introduced, how can it most properly be used here, assuming that Py_RETURN_TRUE/Py_RETURN_FALSE aren't really applicable because a tuple is being returned?


Solution

  • The reason a Py_INCREF is not used here is because Py_BuildValue, when being passed an object with "O" will increment the reference count for you:

    O (object) [PyObject *]

    Pass a Python object untouched (except for its reference count, which is incremented by one). If the object passed in is a NULL pointer, it is assumed that this was caused because the call producing the argument found an error and set an exception. Therefore, Py_BuildValue() will return NULL but won’t raise an exception. If no exception has been raised yet, SystemError is set.

    You'll see a similar usage here in CPython itself for example.