[2.7] bpo-31893: Fixed select.kqueue(). (GH-4166) (#4193)
* Fixed the layout of the kqueue_event structure on OpenBSD and NetBSD.
* Fixed the comparison of the kqueue_event objects..
(cherry picked from commit b9052a0f91d2e83bbc27267247a5920c82b242a3)
diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c
index ce4c15b..1260171 100644
--- a/Modules/selectmodule.c
+++ b/Modules/selectmodule.c
@@ -1221,43 +1221,76 @@
#if (SIZEOF_UINTPTR_T != SIZEOF_VOID_P)
# error uintptr_t does not match void *!
-#elif (SIZEOF_UINTPTR_T == SIZEOF_LONG_LONG)
+#elif defined(HAVE_LONG_LONG) && (SIZEOF_UINTPTR_T == SIZEOF_LONG_LONG)
# define T_UINTPTRT T_ULONGLONG
# define T_INTPTRT T_LONGLONG
-# define PyLong_AsUintptr_t PyLong_AsUnsignedLongLong
# define UINTPTRT_FMT_UNIT "K"
# define INTPTRT_FMT_UNIT "L"
#elif (SIZEOF_UINTPTR_T == SIZEOF_LONG)
# define T_UINTPTRT T_ULONG
# define T_INTPTRT T_LONG
-# define PyLong_AsUintptr_t PyLong_AsUnsignedLong
# define UINTPTRT_FMT_UNIT "k"
# define INTPTRT_FMT_UNIT "l"
#elif (SIZEOF_UINTPTR_T == SIZEOF_INT)
# define T_UINTPTRT T_UINT
# define T_INTPTRT T_INT
-# define PyLong_AsUintptr_t PyLong_AsUnsignedLong
# define UINTPTRT_FMT_UNIT "I"
# define INTPTRT_FMT_UNIT "i"
#else
# error uintptr_t does not match int, long, or long long!
#endif
+#if defined(HAVE_LONG_LONG) && SIZEOF_LONG_LONG == 8
+# define T_INT64 T_LONGLONG
+# define INT64_FMT_UNIT "L"
+#elif SIZEOF_LONG == 8
+# define T_INT64 T_LONG
+# define INT64_FMT_UNIT "l"
+#elif SIZEOF_INT == 8
+# define T_INT64 T_INT
+# define INT64_FMT_UNIT "i"
+#else
+# define INT64_FMT_UNIT "_"
+#endif
+
+#if defined(HAVE_LONG_LONG) && SIZEOF_LONG_LONG == 4
+# define T_UINT32 T_ULONGLONG
+# define UINT32_FMT_UNIT "K"
+#elif SIZEOF_LONG == 4
+# define T_UINT32 T_ULONG
+# define UINT32_FMT_UNIT "k"
+#elif SIZEOF_INT == 4
+# define T_UINT32 T_UINT
+# define UINT32_FMT_UNIT "I"
+#else
+# define UINT32_FMT_UNIT "_"
+#endif
+
/*
* kevent is not standard and its members vary across BSDs.
*/
-#if !defined(__OpenBSD__)
-# define IDENT_TYPE T_UINTPTRT
-# define IDENT_CAST Py_intptr_t
-# define DATA_TYPE T_INTPTRT
-# define DATA_FMT_UNIT INTPTRT_FMT_UNIT
-# define IDENT_AsType PyLong_AsUintptr_t
+#ifdef __NetBSD__
+# define FILTER_TYPE T_UINT32
+# define FILTER_FMT_UNIT UINT32_FMT_UNIT
+# define FLAGS_TYPE T_UINT32
+# define FLAGS_FMT_UNIT UINT32_FMT_UNIT
+# define FFLAGS_TYPE T_UINT32
+# define FFLAGS_FMT_UNIT UINT32_FMT_UNIT
#else
-# define IDENT_TYPE T_UINT
-# define IDENT_CAST int
-# define DATA_TYPE T_INT
-# define DATA_FMT_UNIT "i"
-# define IDENT_AsType PyLong_AsUnsignedLong
+# define FILTER_TYPE T_SHORT
+# define FILTER_FMT_UNIT "h"
+# define FLAGS_TYPE T_USHORT
+# define FLAGS_FMT_UNIT "H"
+# define FFLAGS_TYPE T_UINT
+# define FFLAGS_FMT_UNIT "I"
+#endif
+
+#ifdef __FreeBSD__
+# define DATA_TYPE T_INTPTRT
+# define DATA_FMT_UNIT INTPTR_FMT_UNIT
+#else
+# define DATA_TYPE T_INT64
+# define DATA_FMT_UNIT INT64_FMT_UNIT
#endif
/* Unfortunately, we can't store python objects in udata, because
@@ -1267,9 +1300,9 @@
#define KQ_OFF(x) offsetof(kqueue_event_Object, x)
static struct PyMemberDef kqueue_event_members[] = {
- {"ident", IDENT_TYPE, KQ_OFF(e.ident)},
- {"filter", T_SHORT, KQ_OFF(e.filter)},
- {"flags", T_USHORT, KQ_OFF(e.flags)},
+ {"ident", T_UINTPTRT, KQ_OFF(e.ident)},
+ {"filter", FILTER_TYPE, KQ_OFF(e.filter)},
+ {"flags", FLAGS_TYPE, KQ_OFF(e.flags)},
{"fflags", T_UINT, KQ_OFF(e.fflags)},
{"data", DATA_TYPE, KQ_OFF(e.data)},
{"udata", T_UINTPTRT, KQ_OFF(e.udata)},
@@ -1284,10 +1317,17 @@
char buf[1024];
PyOS_snprintf(
buf, sizeof(buf),
+#ifdef HAVE_LONG_LONG
"<select.kevent ident=%zu filter=%d flags=0x%x fflags=0x%x "
- "data=0x%zd udata=%p>",
- (size_t)(s->e.ident), s->e.filter, s->e.flags,
- s->e.fflags, (Py_ssize_t)(s->e.data), s->e.udata);
+ "data=0x%llx udata=%p>",
+ (size_t)(s->e.ident), (int)s->e.filter, (unsigned int)s->e.flags,
+ (unsigned int)s->e.fflags, (long long)(s->e.data), (void *)s->e.udata);
+#else
+ "<select.kevent ident=%zu filter=%d flags=0x%x fflags=0x%x "
+ "data=0x%llx udata=%p>",
+ (size_t)(s->e.ident), (int)s->e.filter, (unsigned int)s->e.flags,
+ (unsigned int)s->e.fflags, (long)(s->e.data), (void *)s->e.udata);
+#endif
return PyString_FromString(buf);
}
@@ -1297,7 +1337,9 @@
PyObject *pfd;
static char *kwlist[] = {"ident", "filter", "flags", "fflags",
"data", "udata", NULL};
- static char *fmt = "O|hHI" DATA_FMT_UNIT UINTPTRT_FMT_UNIT ":kevent";
+ static const char fmt[] = "O|"
+ FILTER_FMT_UNIT FLAGS_FMT_UNIT FFLAGS_FMT_UNIT DATA_FMT_UNIT
+ UINTPTRT_FMT_UNIT ":kevent";
EV_SET(&(self->e), 0, EVFILT_READ, EV_ADD, 0, 0, 0); /* defaults */
@@ -1307,12 +1349,12 @@
return -1;
}
- if (PyLong_Check(pfd)
-#if IDENT_TYPE == T_UINT
- && PyLong_AsUnsignedLong(pfd) <= UINT_MAX
-#endif
- ) {
- self->e.ident = IDENT_AsType(pfd);
+ if (PyInt_Check(pfd)) {
+ self->e.ident = PyInt_AsUnsignedLongMask(pfd);
+ }
+ else {
+ if (PyInt_Check(pfd) || PyLong_Check(pfd)) {
+ self->e.ident = PyLong_AsSize_t(pfd);
}
else {
self->e.ident = PyObject_AsFileDescriptor(pfd);
@@ -1327,28 +1369,22 @@
kqueue_event_richcompare(kqueue_event_Object *s, kqueue_event_Object *o,
int op)
{
- Py_intptr_t result = 0;
+ int result;
if (!kqueue_event_Check(o)) {
- if (op == Py_EQ || op == Py_NE) {
- PyObject *res = op == Py_EQ ? Py_False : Py_True;
- Py_INCREF(res);
- return res;
- }
- PyErr_Format(PyExc_TypeError,
- "can't compare %.200s to %.200s",
- Py_TYPE(s)->tp_name, Py_TYPE(o)->tp_name);
- return NULL;
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
}
- if (((result = (IDENT_CAST)(s->e.ident - o->e.ident)) == 0) &&
- ((result = s->e.filter - o->e.filter) == 0) &&
- ((result = s->e.flags - o->e.flags) == 0) &&
- ((result = (int)(s->e.fflags - o->e.fflags)) == 0) &&
- ((result = s->e.data - o->e.data) == 0) &&
- ((result = s->e.udata - o->e.udata) == 0)
- ) {
- result = 0;
- }
+
+#define CMP(a, b) ((a) != (b)) ? ((a) < (b) ? -1 : 1)
+ result = CMP(s->e.ident, o->e.ident)
+ : CMP(s->e.filter, o->e.filter)
+ : CMP(s->e.flags, o->e.flags)
+ : CMP(s->e.fflags, o->e.fflags)
+ : CMP(s->e.data, o->e.data)
+ : CMP((Py_intptr_t)s->e.udata, (Py_intptr_t)o->e.udata)
+ : 0;
+#undef CMP
switch (op) {
case Py_EQ: