Mercurial > cpython-lru_cache-weakref
view Python/structmember.c @ 33940:dfd07b7be407 legacy-trunk
SF bug 1061968: threads: segfault or Py_FatalError at exit
PyGILState_Ensure(): The fix in 2.4a3 for bug 1010677 reintroduced thread
shutdown race bug 225673. Repaired by (once again) ensuring the GIL is
held whenever deleting a thread state.
Alas, there's no useful test case for this shy bug. Four years ago, only
Guido could provoke it, on his box, and today only Armin can provoke it
on his box. I've never been able to provoke it (but not for lack of
trying!).
This is a critical fix for 2.3.5 too, since the fix for 1010677 got
backported there already and so also reintroduced 225673. I don't intend to
backport this fix. For whoever (if anyone) does, there are other thread
fixes in 2.4 that need backporting too, and I bet they need to happen first
for this patch to apply cleanly.
| author | Tim Peters <tim.peters@gmail.com> |
|---|---|
| date | Mon, 08 Nov 2004 04:30:21 +0000 |
| parents | 86fdf8fe7f17 |
| children | e9ffad6d8822 |
line wrap: on
line source
/* Map C struct members to Python object attributes */ #include "Python.h" #include "structmember.h" static PyObject * listmembers(struct memberlist *mlist) { int i, n; PyObject *v; for (n = 0; mlist[n].name != NULL; n++) ; v = PyList_New(n); if (v != NULL) { for (i = 0; i < n; i++) PyList_SetItem(v, i, PyString_FromString(mlist[i].name)); if (PyErr_Occurred()) { Py_DECREF(v); v = NULL; } else { PyList_Sort(v); } } return v; } PyObject * PyMember_Get(char *addr, struct memberlist *mlist, char *name) { struct memberlist *l; if (strcmp(name, "__members__") == 0) return listmembers(mlist); for (l = mlist; l->name != NULL; l++) { if (strcmp(l->name, name) == 0) { PyMemberDef copy; copy.name = l->name; copy.type = l->type; copy.offset = l->offset; copy.flags = l->flags; copy.doc = NULL; return PyMember_GetOne(addr, ©); } } PyErr_SetString(PyExc_AttributeError, name); return NULL; } PyObject * PyMember_GetOne(char *addr, PyMemberDef *l) { PyObject *v; if ((l->flags & READ_RESTRICTED) && PyEval_GetRestricted()) { PyErr_SetString(PyExc_RuntimeError, "restricted attribute"); return NULL; } addr += l->offset; switch (l->type) { case T_BYTE: v = PyInt_FromLong( (long) (((*(char*)addr & 0xff) ^ 0x80) - 0x80)); break; case T_UBYTE: v = PyInt_FromLong((long) *(char*)addr & 0xff); break; case T_SHORT: v = PyInt_FromLong((long) *(short*)addr); break; case T_USHORT: v = PyInt_FromLong((long) *(unsigned short*)addr); break; case T_INT: v = PyInt_FromLong((long) *(int*)addr); break; case T_UINT: v = PyInt_FromLong((long) *(unsigned int*)addr); break; case T_LONG: v = PyInt_FromLong(*(long*)addr); break; case T_ULONG: v = PyLong_FromDouble((double) *(unsigned long*)addr); break; case T_FLOAT: v = PyFloat_FromDouble((double)*(float*)addr); break; case T_DOUBLE: v = PyFloat_FromDouble(*(double*)addr); break; case T_STRING: if (*(char**)addr == NULL) { Py_INCREF(Py_None); v = Py_None; } else v = PyString_FromString(*(char**)addr); break; case T_STRING_INPLACE: v = PyString_FromString((char*)addr); break; case T_CHAR: v = PyString_FromStringAndSize((char*)addr, 1); break; case T_OBJECT: v = *(PyObject **)addr; if (v == NULL) v = Py_None; Py_INCREF(v); break; case T_OBJECT_EX: v = *(PyObject **)addr; if (v == NULL) PyErr_SetString(PyExc_AttributeError, l->name); Py_XINCREF(v); break; default: PyErr_SetString(PyExc_SystemError, "bad memberdescr type"); v = NULL; } return v; } int PyMember_Set(char *addr, struct memberlist *mlist, char *name, PyObject *v) { struct memberlist *l; for (l = mlist; l->name != NULL; l++) { if (strcmp(l->name, name) == 0) { PyMemberDef copy; copy.name = l->name; copy.type = l->type; copy.offset = l->offset; copy.flags = l->flags; copy.doc = NULL; return PyMember_SetOne(addr, ©, v); } } PyErr_SetString(PyExc_AttributeError, name); return -1; } int PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v) { PyObject *oldv; if ((l->flags & READONLY) || l->type == T_STRING) { PyErr_SetString(PyExc_TypeError, "readonly attribute"); return -1; } if ((l->flags & WRITE_RESTRICTED) && PyEval_GetRestricted()) { PyErr_SetString(PyExc_RuntimeError, "restricted attribute"); return -1; } if (v == NULL && l->type != T_OBJECT_EX && l->type != T_OBJECT) { PyErr_SetString(PyExc_TypeError, "can't delete numeric/char attribute"); return -1; } addr += l->offset; switch (l->type) { case T_BYTE: case T_UBYTE: if (!PyInt_Check(v)) { PyErr_BadArgument(); return -1; } *(char*)addr = (char) PyInt_AsLong(v); break; case T_SHORT: case T_USHORT: if (!PyInt_Check(v)) { PyErr_BadArgument(); return -1; } *(short*)addr = (short) PyInt_AsLong(v); break; case T_UINT: case T_INT: if (!PyInt_Check(v)) { PyErr_BadArgument(); return -1; } *(int*)addr = (int) PyInt_AsLong(v); break; case T_LONG: if (!PyInt_Check(v)) { PyErr_BadArgument(); return -1; } *(long*)addr = PyInt_AsLong(v); break; case T_ULONG: if (PyInt_Check(v)) *(long*)addr = PyInt_AsLong(v); else if (PyLong_Check(v)) *(long*)addr = PyLong_AsLong(v); else { PyErr_BadArgument(); return -1; } break; case T_FLOAT: if (PyInt_Check(v)) *(float*)addr = (float) PyInt_AsLong(v); else if (PyFloat_Check(v)) *(float*)addr = (float) PyFloat_AsDouble(v); else { PyErr_BadArgument(); return -1; } break; case T_DOUBLE: if (PyInt_Check(v)) *(double*)addr = (double) PyInt_AsLong(v); else if (PyFloat_Check(v)) *(double*)addr = PyFloat_AsDouble(v); else { PyErr_BadArgument(); return -1; } break; case T_OBJECT: case T_OBJECT_EX: Py_XINCREF(v); oldv = *(PyObject **)addr; *(PyObject **)addr = v; Py_XDECREF(oldv); break; case T_CHAR: if (PyString_Check(v) && PyString_Size(v) == 1) { *(char*)addr = PyString_AsString(v)[0]; } else { PyErr_BadArgument(); return -1; } break; default: PyErr_Format(PyExc_SystemError, "bad memberdescr type for %s", l->name); return -1; } return 0; }
