Issue 38037: reference counter issue in signal module (original) (raw)

Adding these two lines to /Objects/longobject.c will disable the "preallocated small integer pool":

#define NSMALLPOSINTS  0
#define NSMALLNEGINTS  0

Then run this reproduce code (attached):

from enum import IntEnum
import _signal

class Handlers(IntEnum):
    A = _signal.SIG_DFL
    B = _signal.SIG_IGN

When the interpreter exits, will get this error:

d:\dev\cpython\PCbuild\win32>python_d.exe d:\a.py
d:\dev\cpython\include\object.h:541: _Py_NegativeRefcount: Assertion failed: object has negative ref count
<object: freed>
Fatal Python error: _PyObject_AssertFailed

Current thread 0x0000200c (most recent call first):

3.8 and 3.9 branches are affected. I'm sorry, this issue is beyond my ability.

This issue is a Python 3.8 regression.

Joannah: Would you mind to have a look?

x = DefaultHandler = PyLong_FromVoidPtr((void *)SIG_DFL);
if (PyModule_AddObject(m, "SIG_DFL", x))
    goto finally;

This change is not easy to read.

DefaultHandler must be a strong reference: finisignal() calls Py_CLEAR(DefaultHandler);

Previously, the code uses PyDict_SetItemString(d, "SIG_DFL", x): PyDict_SetItemString increases the reference counter, whereas PyModule_AddObject leaves the reference counter unchanged (yeah, it's a strange/bad C API).

I guess than an INCREF() is needed somewhere.

Compare it to:

int PyModule_AddIntConstant(PyObject *m, const char *name, long value) { PyObject *o = PyLong_FromLong(value); if (!o) return -1; if (PyModule_AddObject(m, name, o) == 0) return 0; Py_DECREF(o); return -1; }