Skip to content

NumExpr_init() leaks constsig if the itemsizes allocation fails #561

Description

@K-ANOY

NumExpr_init() creates the constants tuple and constsig bytes object before allocating the temporary itemsizes array:

File: numexpr/numexpr_object.cpp

Function: NumExpr_init

if (!(constants = PyTuple_New(n_constants)))
    return -1;
if (!(constsig = PyBytes_FromStringAndSize(NULL, n_constants))) {
    Py_DECREF(constants);
    return -1;
}
if (!(itemsizes = PyMem_New(int, n_constants))) {
    Py_DECREF(constants);
    return -1;
}

PyBytes_FromStringAndSize() returns a new reference. If the following
PyMem_New() call fails, the function releases constants but returns without
releasing constsig.

At this point, constsig is still a local reference and has not been
transferred to self->constsig. Consequently, destruction of the partially
initialized NumExprObject cannot release it.

This is a deterministic cleanup error on the allocation-failure branch, though
the branch normally requires an out-of-memory condition.

To Reproduce

The leak can be confirmed directly from the ownership transitions in
numexpr/numexpr_object.cpp:

  1. PyBytes_FromStringAndSize() returns a new owned reference in constsig.
  2. PyMem_New(int, n_constants) can return NULL.
  3. That failure branch decrements only constants and returns -1.
  4. constsig has not yet been assigned to self->constsig, so no later
    cleanup owns or releases the local reference.

The next failure branch demonstrates the cleanup required at this point:

if (!(o = PySequence_GetItem(o_constants, i))) {
    Py_DECREF(constants);
    Py_DECREF(constsig);
    PyMem_Del(itemsizes);
    return -1;
}

Suggested fix

Release constsig on the itemsizes allocation-failure path:

if (!(itemsizes = PyMem_New(int, n_constants))) {
    Py_DECREF(constants);
    Py_DECREF(constsig);
    return -1;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions