◐ Shell
clean mode source ↗

segfault in mmap object when using __index__ method that closes the mmap

The following (artificial) code segfaults CPython (I tried a bunch of versions, including git main) on my x86 Ubuntu Linux 22.10:

import mmap

with open("abcds", "w+") as f:
    f.write("foobar")
    f.flush()

    class X(object):
        def __index__(self):
            m.close()
            return 1

    m = mmap.mmap(f.fileno(), 6, access=mmap.ACCESS_READ)

    print(m[1])
    print(m[X()])

The problem is this code in mmapmodule.c

static PyObject *
mmap_subscript(mmap_object *self, PyObject *item)
{
    CHECK_VALID(NULL);
    if (PyIndex_Check(item)) {
        Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
        if (i == -1 && PyErr_Occurred())
            return NULL;
        if (i < 0)
            i += self->size;
        if (i < 0 || i >= self->size) {
            PyErr_SetString(PyExc_IndexError,
                "mmap index out of range");
            return NULL;
        }
        return PyLong_FromLong(Py_CHARMASK(self->data[i]));
...

the CHECK_VALID(NULL) call which checks whether the mmap object is closed happens before the PyNumber_AsSsize_t call which closes the object (and similarly for the slice handling which happens further down).

Linked PRs