[New-bugs-announce] [issue11660] closure with too few cells segfaults

Eric Snow report at bugs.python.org
Thu Mar 24 08:00:30 CET 2011


New submission from Eric Snow <ericsnowcurrently at gmail.com>:

While perhaps esoteric, it looks like exec'ing a code object that has freevars, using a closure that has too few cells causes a segfault.  I believe the problem is around line 3276 of ceval.c at the PyTuple_GET_ITEM call:

    if (PyTuple_GET_SIZE(co->co_freevars)) {
        int i;
        for (i = 0; i < PyTuple_GET_SIZE(co->co_freevars); ++i) {
>>>         PyObject *o = PyTuple_GET_ITEM(closure, i);
            Py_INCREF(o);
            freevars[PyTuple_GET_SIZE(co->co_cellvars) + i] = o;
        }
    }

I only bring this up because I am toying around with exposing a wrapper around PyEval_EvalCodeEx that is a more fully featured version of exec.  Here is an example of code where I ran into the problem:

def outer():
    x = 5
    y = 6
    def f(): return x,y
    z = 7
    def g(): return z
    exec_closure(f.__code__, closure=g.__closure__)

Incidently, it looks there isn't any check to see if len(closure) > len(freevars), which I would expect to be disallowed.  However, I understand that there hasn't really been any point to worry about it due to the current usage of PyEval_EvalCodeEx.  

If the above two constraints are appropriate I would love to see them added in with something like the following:

    if (closure == NULL)
        &closure = PyTuple_New(0);
    if (!PyTuple_Check(closure)) {
        PyErr_Format(PyExc_TypeError,
                     "closure must be a tuple");
        goto fail;        
    }
    Py_ssize_t nfreevars = PyTuple_GET_SIZE(co->co_freevars);
    Py_ssize_t ncells = PyTuple_GET_SIZE(closure);
    if (nfreevars != ncells) {
        PyErr_Format(PyExc_SystemError,
                     "Expected %s cells, received %s", 
                     nfreevars, ncells);
        goto fail;        
    }
    if (nfreevars) {
        int i;
        for (i = 0; i < PyTuple_GET_SIZE(co->co_freevars); ++i) {
            PyObject *o = PyTuple_GET_ITEM(closure, i);
            Py_INCREF(o);
            freevars[PyTuple_GET_SIZE(co->co_cellvars) + i] = o;
        }
    }

Alternately, I could just add some validation into exec_closure, if it's not worth bothering in ceval.c.

----------
components: Interpreter Core
messages: 131961
nosy: ericsnow
priority: normal
severity: normal
status: open
title: closure with too few cells segfaults
type: crash
versions: Python 3.3

_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue11660>
_______________________________________


More information about the New-bugs-announce mailing list