From cacf1e84f7dd5091159bc6d96dde52c5cc587c2c Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 15 Feb 2023 15:52:38 +0100 Subject: [PATCH 01/15] Consistency: use explicit initialiser for m_base --- Modules/_datetimemodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 0d356779cfe192..c687d9ae811bfb 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6913,7 +6913,7 @@ _datetime_exec(PyObject *module) } static struct PyModuleDef datetimemodule = { - PyModuleDef_HEAD_INIT, + .m_base = PyModuleDef_HEAD_INIT, .m_name = "_datetime", .m_doc = "Fast implementation of the datetime type.", .m_size = -1, From c2eba8fcf2be2ae0ca228baa6092c284fda2acfa Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 15 Feb 2023 15:57:15 +0100 Subject: [PATCH 02/15] Add module state stub; establish global state on stack --- Modules/_datetimemodule.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index c687d9ae811bfb..fe7e30a94d981b 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -40,6 +40,13 @@ #define PyTimezone_Check(op) PyObject_TypeCheck(op, &PyDateTime_TimeZoneType) +typedef struct { +} datetime_state; + +static datetime_state global_state; + +#define GLOBAL_STATE() (&global_state) + /*[clinic input] module datetime class datetime.datetime "PyDateTime_DateTime *" "&PyDateTime_DateTimeType" From 8d54ecdc4e71e6f7dcfbb0ee3d5aa9cbc729453a Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 15 Feb 2023 16:03:13 +0100 Subject: [PATCH 03/15] Put conversion factors in state struct --- Modules/_datetimemodule.c | 89 ++++++++++----------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 7 -- 2 files changed, 44 insertions(+), 52 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index fe7e30a94d981b..f6e9a6ca6449ee 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -41,6 +41,14 @@ #define PyTimezone_Check(op) PyObject_TypeCheck(op, &PyDateTime_TimeZoneType) typedef struct { + /* Conversion factors. */ + PyObject *us_per_ms; // 1000 + PyObject *us_per_second; // 1000000 + PyObject *us_per_minute; // 1e6 * 60 as Python int + PyObject *us_per_hour; // 1e6 * 3600 as Python int + PyObject *us_per_day; // 1e6 * 3600 * 24 as Python int + PyObject *us_per_week; // 1e6*3600*24*7 as Python int + PyObject *seconds_per_day; // 3600*24 as Python int } datetime_state; static datetime_state global_state; @@ -1814,19 +1822,6 @@ cmperror(PyObject *a, PyObject *b) return NULL; } -/* --------------------------------------------------------------------------- - * Cached Python objects; these are set by the module init function. - */ - -/* Conversion factors. */ -static PyObject *us_per_ms = NULL; /* 1000 */ -static PyObject *us_per_second = NULL; /* 1000000 */ -static PyObject *us_per_minute = NULL; /* 1e6 * 60 as Python int */ -static PyObject *us_per_hour = NULL; /* 1e6 * 3600 as Python int */ -static PyObject *us_per_day = NULL; /* 1e6 * 3600 * 24 as Python int */ -static PyObject *us_per_week = NULL; /* 1e6*3600*24*7 as Python int */ -static PyObject *seconds_per_day = NULL; /* 3600*24 as Python int */ - /* --------------------------------------------------------------------------- * Class implementations. */ @@ -1852,7 +1847,8 @@ delta_to_microseconds(PyDateTime_Delta *self) x1 = PyLong_FromLong(GET_TD_DAYS(self)); if (x1 == NULL) goto Done; - x2 = PyNumber_Multiply(x1, seconds_per_day); /* days in seconds */ + datetime_state *st = GLOBAL_STATE(); + x2 = PyNumber_Multiply(x1, st->seconds_per_day); /* days in seconds */ if (x2 == NULL) goto Done; Py_SETREF(x1, NULL); @@ -1869,7 +1865,7 @@ delta_to_microseconds(PyDateTime_Delta *self) /* x1 = */ x2 = NULL; /* x3 has days+seconds in seconds */ - x1 = PyNumber_Multiply(x3, us_per_second); /* us */ + x1 = PyNumber_Multiply(x3, st->us_per_second); /* us */ if (x1 == NULL) goto Done; Py_SETREF(x3, NULL); @@ -1924,7 +1920,8 @@ microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type) PyObject *num = NULL; PyObject *result = NULL; - tuple = checked_divmod(pyus, us_per_second); + datetime_state *st = GLOBAL_STATE(); + tuple = checked_divmod(pyus, st->us_per_second); if (tuple == NULL) { goto Done; } @@ -1942,7 +1939,7 @@ microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type) num = Py_NewRef(PyTuple_GET_ITEM(tuple, 0)); /* leftover seconds */ Py_DECREF(tuple); - tuple = checked_divmod(num, seconds_per_day); + tuple = checked_divmod(num, st->seconds_per_day); if (tuple == NULL) goto Done; Py_DECREF(num); @@ -2542,28 +2539,29 @@ delta_new(PyTypeObject *type, PyObject *args, PyObject *kw) y = accum("microseconds", x, us, _PyLong_GetOne(), &leftover_us); CLEANUP; } + datetime_state *st = GLOBAL_STATE(); if (ms) { - y = accum("milliseconds", x, ms, us_per_ms, &leftover_us); + y = accum("milliseconds", x, ms, st->us_per_ms, &leftover_us); CLEANUP; } if (second) { - y = accum("seconds", x, second, us_per_second, &leftover_us); + y = accum("seconds", x, second, st->us_per_second, &leftover_us); CLEANUP; } if (minute) { - y = accum("minutes", x, minute, us_per_minute, &leftover_us); + y = accum("minutes", x, minute, st->us_per_minute, &leftover_us); CLEANUP; } if (hour) { - y = accum("hours", x, hour, us_per_hour, &leftover_us); + y = accum("hours", x, hour, st->us_per_hour, &leftover_us); CLEANUP; } if (day) { - y = accum("days", x, day, us_per_day, &leftover_us); + y = accum("days", x, day, st->us_per_day, &leftover_us); CLEANUP; } if (week) { - y = accum("weeks", x, week, us_per_week, &leftover_us); + y = accum("weeks", x, week, st->us_per_week, &leftover_us); CLEANUP; } if (leftover_us) { @@ -2718,7 +2716,8 @@ delta_total_seconds(PyObject *self, PyObject *Py_UNUSED(ignored)) if (total_microseconds == NULL) return NULL; - total_seconds = PyNumber_TrueDivide(total_microseconds, us_per_second); + datetime_state *st = GLOBAL_STATE(); + total_seconds = PyNumber_TrueDivide(total_microseconds, st->us_per_second); Py_DECREF(total_microseconds); return total_seconds; @@ -6873,49 +6872,49 @@ _datetime_exec(PyObject *module) static_assert(DI100Y == 25 * DI4Y - 1, "DI100Y"); assert(DI100Y == days_before_year(100+1)); - us_per_ms = PyLong_FromLong(1000); - if (us_per_ms == NULL) { + st->us_per_ms = PyLong_FromLong(1000); + if (st->us_per_ms == NULL) { goto error; } - us_per_second = PyLong_FromLong(1000000); - if (us_per_second == NULL) { + st->us_per_second = PyLong_FromLong(1000000); + if (st->us_per_second == NULL) { goto error; } - us_per_minute = PyLong_FromLong(60000000); - if (us_per_minute == NULL) { + st->us_per_minute = PyLong_FromLong(60000000); + if (st->us_per_minute == NULL) { goto error; } - seconds_per_day = PyLong_FromLong(24 * 3600); - if (seconds_per_day == NULL) { + st->seconds_per_day = PyLong_FromLong(24 * 3600); + if (st->seconds_per_day == NULL) { goto error; } /* The rest are too big for 32-bit ints, but even * us_per_week fits in 40 bits, so doubles should be exact. */ - us_per_hour = PyLong_FromDouble(3600000000.0); - if (us_per_hour == NULL) { + st->us_per_hour = PyLong_FromDouble(3600000000.0); + if (st->us_per_hour == NULL) { goto error; } - us_per_day = PyLong_FromDouble(86400000000.0); - if (us_per_day == NULL) { + st->us_per_day = PyLong_FromDouble(86400000000.0); + if (st->us_per_day == NULL) { goto error; } - us_per_week = PyLong_FromDouble(604800000000.0); - if (us_per_week == NULL) { + st->us_per_week = PyLong_FromDouble(604800000000.0); + if (st->us_per_week == NULL) { goto error; } return 0; error: - Py_XDECREF(us_per_ms); - Py_XDECREF(us_per_second); - Py_XDECREF(us_per_minute); - Py_XDECREF(us_per_hour); - Py_XDECREF(us_per_day); - Py_XDECREF(us_per_week); - Py_XDECREF(seconds_per_day); + Py_CLEAR(st->us_per_ms); + Py_CLEAR(st->us_per_second); + Py_CLEAR(st->us_per_minute); + Py_CLEAR(st->us_per_hour); + Py_CLEAR(st->us_per_day); + Py_CLEAR(st->us_per_week); + Py_CLEAR(st->seconds_per_day); return -1; } diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index bb85fba895bc25..79889ae6d7e023 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -420,13 +420,6 @@ Modules/_cursesmodule.c - ModDict - Modules/_datetimemodule.c datetime_strptime module - Modules/_datetimemodule.c - PyDateTime_TimeZone_UTC - Modules/_datetimemodule.c - PyDateTime_Epoch - -Modules/_datetimemodule.c - us_per_ms - -Modules/_datetimemodule.c - us_per_second - -Modules/_datetimemodule.c - us_per_minute - -Modules/_datetimemodule.c - us_per_hour - -Modules/_datetimemodule.c - us_per_day - -Modules/_datetimemodule.c - us_per_week - -Modules/_datetimemodule.c - seconds_per_day - ## state Modules/_ctypes/_ctypes.c - _ctypes_ptrtype_cache - From 360397a30f4f77abe01b4233fe88006f6d2b13b1 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 15 Feb 2023 17:00:07 +0100 Subject: [PATCH 04/15] Move PyDateTime_TimeZone_UTC to state --- Modules/_datetimemodule.c | 34 +++++++++++++-------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index f6e9a6ca6449ee..39ba4a760356da 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -49,6 +49,9 @@ typedef struct { PyObject *us_per_day; // 1e6 * 3600 * 24 as Python int PyObject *us_per_week; // 1e6*3600*24*7 as Python int PyObject *seconds_per_day; // 3600*24 as Python int + + /* The interned UTC timezone instance */ + PyObject *PyDateTime_TimeZone_UTC; } datetime_state; static datetime_state global_state; @@ -1154,8 +1157,6 @@ typedef struct PyObject *name; } PyDateTime_TimeZone; -/* The interned UTC timezone instance */ -static PyObject *PyDateTime_TimeZone_UTC; /* The interned Epoch datetime instance */ static PyObject *PyDateTime_Epoch; @@ -1192,7 +1193,8 @@ new_timezone(PyObject *offset, PyObject *name) assert(name == NULL || PyUnicode_Check(name)); if (name == NULL && delta_bool((PyDateTime_Delta *)offset) == 0) { - return Py_NewRef(PyDateTime_TimeZone_UTC); + datetime_state *st = GLOBAL_STATE(); + return Py_NewRef(st->PyDateTime_TimeZone_UTC); } if ((GET_TD_DAYS(offset) == -1 && GET_TD_SECONDS(offset) == 0 && @@ -1405,7 +1407,8 @@ tzinfo_from_isoformat_results(int rv, int tzoffset, int tz_useconds) if (rv == 1) { // Create a timezone from offset in seconds (0 returns UTC) if (tzoffset == 0) { - return Py_NewRef(PyDateTime_TimeZone_UTC); + datetime_state *st = GLOBAL_STATE(); + return Py_NewRef(st->PyDateTime_TimeZone_UTC); } PyObject *delta = new_delta(0, tzoffset, tz_useconds, 1); @@ -3949,7 +3952,8 @@ timezone_repr(PyDateTime_TimeZone *self) to use Py_TYPE(self)->tp_name here. */ const char *type_name = Py_TYPE(self)->tp_name; - if (((PyObject *)self) == PyDateTime_TimeZone_UTC) + datetime_state *st = GLOBAL_STATE(); + if (((PyObject *)self) == st->PyDateTime_TimeZone_UTC) return PyUnicode_FromFormat("%s.utc", type_name); if (self->name == NULL) @@ -3970,7 +3974,8 @@ timezone_str(PyDateTime_TimeZone *self) if (self->name != NULL) { return Py_NewRef(self->name); } - if ((PyObject *)self == PyDateTime_TimeZone_UTC || + datetime_state *st = GLOBAL_STATE(); + if ((PyObject *)self == st->PyDateTime_TimeZone_UTC || (GET_TD_DAYS(self->offset) == 0 && GET_TD_SECONDS(self->offset) == 0 && GET_TD_MICROSECONDS(self->offset) == 0)) @@ -6252,6 +6257,7 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) if (result == NULL) return NULL; + datetime_state *st = GLOBAL_STATE(); /* Make sure result is aware and UTC. */ if (!HASTZINFO(result)) { temp = (PyObject *)result; @@ -6263,7 +6269,7 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) DATE_GET_MINUTE(result), DATE_GET_SECOND(result), DATE_GET_MICROSECOND(result), - PyDateTime_TimeZone_UTC, + st->PyDateTime_TimeZone_UTC, DATE_GET_FOLD(result), Py_TYPE(result)); Py_DECREF(temp); @@ -6272,7 +6278,7 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) } else { /* Result is already aware - just replace tzinfo. */ - Py_SETREF(result->tzinfo, Py_NewRef(PyDateTime_TimeZone_UTC)); + Py_SETREF(result->tzinfo, Py_NewRef(st->PyDateTime_TimeZone_UTC)); } /* Attach new tzinfo and let fromutc() do the rest. */ @@ -6700,8 +6706,9 @@ get_datetime_capi(void) capi->Time_FromTimeAndFold = new_time_ex2; // Make sure this function is called after PyDateTime_TimeZone_UTC has // been initialized. - assert(PyDateTime_TimeZone_UTC != NULL); - capi->TimeZone_UTC = PyDateTime_TimeZone_UTC; // borrowed ref + datetime_state *st = GLOBAL_STATE(); + assert(st->PyDateTime_TimeZone_UTC != NULL); + capi->TimeZone_UTC = st->PyDateTime_TimeZone_UTC; // borrowed ref return capi; } @@ -6798,7 +6805,8 @@ _datetime_exec(PyObject *module) return -1; } - PyDateTime_TimeZone_UTC = x; + datetime_state *st = GLOBAL_STATE(); + st->PyDateTime_TimeZone_UTC = x; /* bpo-37642: These attributes are rounded to the nearest minute for backwards * compatibility, even though the constructor will accept a wider range of @@ -6823,7 +6831,7 @@ _datetime_exec(PyObject *module) /* Epoch */ PyDateTime_Epoch = new_datetime(1970, 1, 1, 0, 0, 0, 0, - PyDateTime_TimeZone_UTC, 0); + st->PyDateTime_TimeZone_UTC, 0); if (PyDateTime_Epoch == NULL) { return -1; } @@ -6850,7 +6858,7 @@ _datetime_exec(PyObject *module) return -1; } - if (PyModule_AddObjectRef(module, "UTC", PyDateTime_TimeZone_UTC) < 0) { + if (PyModule_AddObjectRef(module, "UTC", st->PyDateTime_TimeZone_UTC) < 0) { return -1; } diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 79889ae6d7e023..bedee61fa85567 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -418,7 +418,6 @@ Modules/_ctypes/_ctypes.c - _unpickle - Modules/_ctypes/_ctypes.c PyCArrayType_from_ctype cache - Modules/_cursesmodule.c - ModDict - Modules/_datetimemodule.c datetime_strptime module - -Modules/_datetimemodule.c - PyDateTime_TimeZone_UTC - Modules/_datetimemodule.c - PyDateTime_Epoch - ## state From 4f509f9fa586991db27a7d831ed9d552851c7f6d Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 15 Feb 2023 20:51:17 +0100 Subject: [PATCH 05/15] Move PyDateTime_Epoch to state struct --- Modules/_datetimemodule.c | 16 +++++++++------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 39ba4a760356da..438271f49d7f3e 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -52,6 +52,9 @@ typedef struct { /* The interned UTC timezone instance */ PyObject *PyDateTime_TimeZone_UTC; + + /* The interned Epoch datetime instance */ + PyObject *PyDateTime_Epoch; } datetime_state; static datetime_state global_state; @@ -1157,9 +1160,6 @@ typedef struct PyObject *name; } PyDateTime_TimeZone; -/* The interned Epoch datetime instance */ -static PyObject *PyDateTime_Epoch; - /* Create new timezone instance checking offset range. This function does not check the name argument. Caller must assure that offset is a timedelta instance and name is either NULL @@ -6145,7 +6145,8 @@ local_timezone(PyDateTime_DateTime *utc_time) PyObject *one_second; PyObject *seconds; - delta = datetime_subtract((PyObject *)utc_time, PyDateTime_Epoch); + datetime_state *st = GLOBAL_STATE(); + delta = datetime_subtract((PyObject *)utc_time, st->PyDateTime_Epoch); if (delta == NULL) return NULL; one_second = new_delta(0, 1, 0, 0); @@ -6382,8 +6383,9 @@ datetime_timestamp(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) PyObject *result; if (HASTZINFO(self) && self->tzinfo != Py_None) { + datetime_state *st = GLOBAL_STATE(); PyObject *delta; - delta = datetime_subtract((PyObject *)self, PyDateTime_Epoch); + delta = datetime_subtract((PyObject *)self, st->PyDateTime_Epoch); if (delta == NULL) return NULL; result = delta_total_seconds(delta, NULL); @@ -6830,9 +6832,9 @@ _datetime_exec(PyObject *module) DATETIME_ADD_MACRO(d, "max", x); /* Epoch */ - PyDateTime_Epoch = new_datetime(1970, 1, 1, 0, 0, 0, 0, + st->PyDateTime_Epoch = new_datetime(1970, 1, 1, 0, 0, 0, 0, st->PyDateTime_TimeZone_UTC, 0); - if (PyDateTime_Epoch == NULL) { + if (st->PyDateTime_Epoch == NULL) { return -1; } diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index bedee61fa85567..e85c454bcc81e9 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -418,7 +418,6 @@ Modules/_ctypes/_ctypes.c - _unpickle - Modules/_ctypes/_ctypes.c PyCArrayType_from_ctype cache - Modules/_cursesmodule.c - ModDict - Modules/_datetimemodule.c datetime_strptime module - -Modules/_datetimemodule.c - PyDateTime_Epoch - ## state Modules/_ctypes/_ctypes.c - _ctypes_ptrtype_cache - From 6b14c8cac3bae3217e30fde5efd49d3e5fcb2cf0 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 15 Feb 2023 20:52:25 +0100 Subject: [PATCH 06/15] Remove datetime_strptime globals entry --- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 1 file changed, 1 deletion(-) diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index e85c454bcc81e9..17dbfb6fefff02 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -417,7 +417,6 @@ Modules/_ctypes/_ctypes.c CreateSwappedType suffix - Modules/_ctypes/_ctypes.c - _unpickle - Modules/_ctypes/_ctypes.c PyCArrayType_from_ctype cache - Modules/_cursesmodule.c - ModDict - -Modules/_datetimemodule.c datetime_strptime module - ## state Modules/_ctypes/_ctypes.c - _ctypes_ptrtype_cache - From 2eb3315327f6d1de711fb8bc8309eb8ec236afeb Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 6 Oct 2023 15:58:37 +0200 Subject: [PATCH 07/15] Apply Victor's suggestions from gh-102995 --- Modules/_datetimemodule.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 438271f49d7f3e..669c76be89942e 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -42,13 +42,13 @@ typedef struct { /* Conversion factors. */ - PyObject *us_per_ms; // 1000 - PyObject *us_per_second; // 1000000 + PyObject *us_per_ms; // 1_000 + PyObject *us_per_second; // 1_000_000 PyObject *us_per_minute; // 1e6 * 60 as Python int PyObject *us_per_hour; // 1e6 * 3600 as Python int PyObject *us_per_day; // 1e6 * 3600 * 24 as Python int - PyObject *us_per_week; // 1e6*3600*24*7 as Python int - PyObject *seconds_per_day; // 3600*24 as Python int + PyObject *us_per_week; // 1e6 * 3600 * 24 * 7 as Python int + PyObject *seconds_per_day; // 3600 * 24 as Python int /* The interned UTC timezone instance */ PyObject *PyDateTime_TimeZone_UTC; From f5ede1e9bb477c1618dbb6b16c3a02982c77afc4 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 6 Oct 2023 16:01:15 +0200 Subject: [PATCH 08/15] Apply PEP-7 to modified code --- Modules/_datetimemodule.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 669c76be89942e..56d36221d374a8 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -3953,8 +3953,9 @@ timezone_repr(PyDateTime_TimeZone *self) const char *type_name = Py_TYPE(self)->tp_name; datetime_state *st = GLOBAL_STATE(); - if (((PyObject *)self) == st->PyDateTime_TimeZone_UTC) + if (((PyObject *)self) == st->PyDateTime_TimeZone_UTC) { return PyUnicode_FromFormat("%s.utc", type_name); + } if (self->name == NULL) return PyUnicode_FromFormat("%s(%R)", type_name, self->offset); @@ -3979,7 +3980,9 @@ timezone_str(PyDateTime_TimeZone *self) (GET_TD_DAYS(self->offset) == 0 && GET_TD_SECONDS(self->offset) == 0 && GET_TD_MICROSECONDS(self->offset) == 0)) + { return PyUnicode_FromString("UTC"); + } /* Offset is normalized, so it is negative if days < 0 */ if (GET_TD_DAYS(self->offset) < 0) { sign = '-'; From 713956903195bb798b0c3f58a5d103cb83f173be Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 6 Oct 2023 17:05:26 +0200 Subject: [PATCH 09/15] Fix check-c-globals --- Tools/c-analyzer/cpython/globals-to-fix.tsv | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 17dbfb6fefff02..edb45bbd3dad76 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -417,11 +417,13 @@ Modules/_ctypes/_ctypes.c CreateSwappedType suffix - Modules/_ctypes/_ctypes.c - _unpickle - Modules/_ctypes/_ctypes.c PyCArrayType_from_ctype cache - Modules/_cursesmodule.c - ModDict - +Modules/_datetimemodule.c datetime_strptime module - ## state Modules/_ctypes/_ctypes.c - _ctypes_ptrtype_cache - Modules/_ctypes/_ctypes.c - global_state - Modules/_ctypes/ctypes.h - global_state - +Modules/_datetimemodule.c - global_state - Modules/_tkinter.c - tcl_lock - Modules/_tkinter.c - excInCmd - Modules/_tkinter.c - valInCmd - From beb0977b0e1924f2eaa784fd5efd81b9b2136be2 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 11 Oct 2023 00:53:00 +0200 Subject: [PATCH 10/15] Address review: use shorter names --- Modules/_datetimemodule.c | 45 +++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 56d36221d374a8..c8765a1919f8fe 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -51,10 +51,10 @@ typedef struct { PyObject *seconds_per_day; // 3600 * 24 as Python int /* The interned UTC timezone instance */ - PyObject *PyDateTime_TimeZone_UTC; + PyObject *utc; /* The interned Epoch datetime instance */ - PyObject *PyDateTime_Epoch; + PyObject *epoch; } datetime_state; static datetime_state global_state; @@ -1194,7 +1194,7 @@ new_timezone(PyObject *offset, PyObject *name) if (name == NULL && delta_bool((PyDateTime_Delta *)offset) == 0) { datetime_state *st = GLOBAL_STATE(); - return Py_NewRef(st->PyDateTime_TimeZone_UTC); + return Py_NewRef(st->utc); } if ((GET_TD_DAYS(offset) == -1 && GET_TD_SECONDS(offset) == 0 && @@ -1408,7 +1408,7 @@ tzinfo_from_isoformat_results(int rv, int tzoffset, int tz_useconds) // Create a timezone from offset in seconds (0 returns UTC) if (tzoffset == 0) { datetime_state *st = GLOBAL_STATE(); - return Py_NewRef(st->PyDateTime_TimeZone_UTC); + return Py_NewRef(st->utc); } PyObject *delta = new_delta(0, tzoffset, tz_useconds, 1); @@ -3953,7 +3953,7 @@ timezone_repr(PyDateTime_TimeZone *self) const char *type_name = Py_TYPE(self)->tp_name; datetime_state *st = GLOBAL_STATE(); - if (((PyObject *)self) == st->PyDateTime_TimeZone_UTC) { + if (((PyObject *)self) == st->utc) { return PyUnicode_FromFormat("%s.utc", type_name); } @@ -3976,7 +3976,7 @@ timezone_str(PyDateTime_TimeZone *self) return Py_NewRef(self->name); } datetime_state *st = GLOBAL_STATE(); - if ((PyObject *)self == st->PyDateTime_TimeZone_UTC || + if ((PyObject *)self == st->utc || (GET_TD_DAYS(self->offset) == 0 && GET_TD_SECONDS(self->offset) == 0 && GET_TD_MICROSECONDS(self->offset) == 0)) @@ -6149,7 +6149,7 @@ local_timezone(PyDateTime_DateTime *utc_time) PyObject *seconds; datetime_state *st = GLOBAL_STATE(); - delta = datetime_subtract((PyObject *)utc_time, st->PyDateTime_Epoch); + delta = datetime_subtract((PyObject *)utc_time, st->epoch); if (delta == NULL) return NULL; one_second = new_delta(0, 1, 0, 0); @@ -6273,7 +6273,7 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) DATE_GET_MINUTE(result), DATE_GET_SECOND(result), DATE_GET_MICROSECOND(result), - st->PyDateTime_TimeZone_UTC, + st->utc, DATE_GET_FOLD(result), Py_TYPE(result)); Py_DECREF(temp); @@ -6282,7 +6282,7 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) } else { /* Result is already aware - just replace tzinfo. */ - Py_SETREF(result->tzinfo, Py_NewRef(st->PyDateTime_TimeZone_UTC)); + Py_SETREF(result->tzinfo, Py_NewRef(st->utc)); } /* Attach new tzinfo and let fromutc() do the rest. */ @@ -6388,7 +6388,7 @@ datetime_timestamp(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) if (HASTZINFO(self) && self->tzinfo != Py_None) { datetime_state *st = GLOBAL_STATE(); PyObject *delta; - delta = datetime_subtract((PyObject *)self, st->PyDateTime_Epoch); + delta = datetime_subtract((PyObject *)self, st->epoch); if (delta == NULL) return NULL; result = delta_total_seconds(delta, NULL); @@ -6709,11 +6709,11 @@ get_datetime_capi(void) capi->Date_FromTimestamp = datetime_date_fromtimestamp_capi; capi->DateTime_FromDateAndTimeAndFold = new_datetime_ex2; capi->Time_FromTimeAndFold = new_time_ex2; - // Make sure this function is called after PyDateTime_TimeZone_UTC has + // Make sure this function is called after utc has // been initialized. datetime_state *st = GLOBAL_STATE(); - assert(st->PyDateTime_TimeZone_UTC != NULL); - capi->TimeZone_UTC = st->PyDateTime_TimeZone_UTC; // borrowed ref + assert(st->utc != NULL); + capi->TimeZone_UTC = st->utc; // borrowed ref return capi; } @@ -6800,18 +6800,18 @@ _datetime_exec(PyObject *module) return -1; } - PyObject *x = create_timezone(delta, NULL); + PyObject *utc = create_timezone(delta, NULL); Py_DECREF(delta); - if (x == NULL) { + if (utc == NULL) { return -1; } - if (PyDict_SetItemString(d, "utc", x) < 0) { - Py_DECREF(x); + if (PyDict_SetItemString(d, "utc", utc) < 0) { + Py_DECREF(utc); return -1; } datetime_state *st = GLOBAL_STATE(); - st->PyDateTime_TimeZone_UTC = x; + st->utc = utc; /* bpo-37642: These attributes are rounded to the nearest minute for backwards * compatibility, even though the constructor will accept a wider range of @@ -6821,7 +6821,7 @@ _datetime_exec(PyObject *module) return -1; } - x = create_timezone(delta, NULL); + PyObject *x = create_timezone(delta, NULL); Py_DECREF(delta); DATETIME_ADD_MACRO(d, "min", x); @@ -6835,9 +6835,8 @@ _datetime_exec(PyObject *module) DATETIME_ADD_MACRO(d, "max", x); /* Epoch */ - st->PyDateTime_Epoch = new_datetime(1970, 1, 1, 0, 0, 0, 0, - st->PyDateTime_TimeZone_UTC, 0); - if (st->PyDateTime_Epoch == NULL) { + st->epoch = new_datetime(1970, 1, 1, 0, 0, 0, 0, st->utc, 0); + if (st->epoch == NULL) { return -1; } @@ -6863,7 +6862,7 @@ _datetime_exec(PyObject *module) return -1; } - if (PyModule_AddObjectRef(module, "UTC", st->PyDateTime_TimeZone_UTC) < 0) { + if (PyModule_AddObjectRef(module, "UTC", st->utc) < 0) { return -1; } From 6863f763c07909fa3e921e933d2ed68091b603a6 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 11 Oct 2023 11:51:02 +0200 Subject: [PATCH 11/15] Address review: rename global_state => _datetime_global_state --- Modules/_datetimemodule.c | 4 ++-- Tools/c-analyzer/cpython/globals-to-fix.tsv | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index c8765a1919f8fe..c7331a0a922b9f 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -57,9 +57,9 @@ typedef struct { PyObject *epoch; } datetime_state; -static datetime_state global_state; +static datetime_state _datetime_global_state; -#define GLOBAL_STATE() (&global_state) +#define GLOBAL_STATE() (&_datetime_global_state) /*[clinic input] module datetime diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index edb45bbd3dad76..aa8ce49ae86376 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -423,7 +423,7 @@ Modules/_datetimemodule.c datetime_strptime module - Modules/_ctypes/_ctypes.c - _ctypes_ptrtype_cache - Modules/_ctypes/_ctypes.c - global_state - Modules/_ctypes/ctypes.h - global_state - -Modules/_datetimemodule.c - global_state - +Modules/_datetimemodule.c - _datetime_global_state - Modules/_tkinter.c - tcl_lock - Modules/_tkinter.c - excInCmd - Modules/_tkinter.c - valInCmd - From c56b5e1fa7673705a1806abb8779058f1deca5e2 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 11 Oct 2023 15:43:19 +0200 Subject: [PATCH 12/15] Address review --- Modules/_datetimemodule.c | 57 +++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index c7331a0a922b9f..5c26ba51399f5d 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -53,13 +53,13 @@ typedef struct { /* The interned UTC timezone instance */ PyObject *utc; - /* The interned Epoch datetime instance */ + /* The interned Unix epoch datetime instance */ PyObject *epoch; } datetime_state; static datetime_state _datetime_global_state; -#define GLOBAL_STATE() (&_datetime_global_state) +#define STATIC_STATE() (&_datetime_global_state) /*[clinic input] module datetime @@ -1193,7 +1193,7 @@ new_timezone(PyObject *offset, PyObject *name) assert(name == NULL || PyUnicode_Check(name)); if (name == NULL && delta_bool((PyDateTime_Delta *)offset) == 0) { - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = STATIC_STATE(); return Py_NewRef(st->utc); } if ((GET_TD_DAYS(offset) == -1 && @@ -1407,7 +1407,7 @@ tzinfo_from_isoformat_results(int rv, int tzoffset, int tz_useconds) if (rv == 1) { // Create a timezone from offset in seconds (0 returns UTC) if (tzoffset == 0) { - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = STATIC_STATE(); return Py_NewRef(st->utc); } @@ -1850,7 +1850,7 @@ delta_to_microseconds(PyDateTime_Delta *self) x1 = PyLong_FromLong(GET_TD_DAYS(self)); if (x1 == NULL) goto Done; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = STATIC_STATE(); x2 = PyNumber_Multiply(x1, st->seconds_per_day); /* days in seconds */ if (x2 == NULL) goto Done; @@ -1923,7 +1923,7 @@ microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type) PyObject *num = NULL; PyObject *result = NULL; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = STATIC_STATE(); tuple = checked_divmod(pyus, st->us_per_second); if (tuple == NULL) { goto Done; @@ -2542,7 +2542,7 @@ delta_new(PyTypeObject *type, PyObject *args, PyObject *kw) y = accum("microseconds", x, us, _PyLong_GetOne(), &leftover_us); CLEANUP; } - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = STATIC_STATE(); if (ms) { y = accum("milliseconds", x, ms, st->us_per_ms, &leftover_us); CLEANUP; @@ -2719,7 +2719,7 @@ delta_total_seconds(PyObject *self, PyObject *Py_UNUSED(ignored)) if (total_microseconds == NULL) return NULL; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = STATIC_STATE(); total_seconds = PyNumber_TrueDivide(total_microseconds, st->us_per_second); Py_DECREF(total_microseconds); @@ -3952,7 +3952,7 @@ timezone_repr(PyDateTime_TimeZone *self) to use Py_TYPE(self)->tp_name here. */ const char *type_name = Py_TYPE(self)->tp_name; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = STATIC_STATE(); if (((PyObject *)self) == st->utc) { return PyUnicode_FromFormat("%s.utc", type_name); } @@ -3975,7 +3975,7 @@ timezone_str(PyDateTime_TimeZone *self) if (self->name != NULL) { return Py_NewRef(self->name); } - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = STATIC_STATE(); if ((PyObject *)self == st->utc || (GET_TD_DAYS(self->offset) == 0 && GET_TD_SECONDS(self->offset) == 0 && @@ -6148,7 +6148,7 @@ local_timezone(PyDateTime_DateTime *utc_time) PyObject *one_second; PyObject *seconds; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = STATIC_STATE(); delta = datetime_subtract((PyObject *)utc_time, st->epoch); if (delta == NULL) return NULL; @@ -6261,7 +6261,7 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) if (result == NULL) return NULL; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = STATIC_STATE(); /* Make sure result is aware and UTC. */ if (!HASTZINFO(result)) { temp = (PyObject *)result; @@ -6386,7 +6386,7 @@ datetime_timestamp(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) PyObject *result; if (HASTZINFO(self) && self->tzinfo != Py_None) { - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = STATIC_STATE(); PyObject *delta; delta = datetime_subtract((PyObject *)self, st->epoch); if (delta == NULL) @@ -6711,7 +6711,7 @@ get_datetime_capi(void) capi->Time_FromTimeAndFold = new_time_ex2; // Make sure this function is called after utc has // been initialized. - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = STATIC_STATE(); assert(st->utc != NULL); capi->TimeZone_UTC = st->utc; // borrowed ref return capi; @@ -6724,6 +6724,23 @@ datetime_destructor(PyObject *op) PyMem_Free(ptr); } +static int +datetime_clear(PyObject *module) +{ + datetime_state *st = STATIC_STATE(); + + Py_CLEAR(st->us_per_ms); + Py_CLEAR(st->us_per_second); + Py_CLEAR(st->us_per_minute); + Py_CLEAR(st->us_per_hour); + Py_CLEAR(st->us_per_day); + Py_CLEAR(st->us_per_week); + Py_CLEAR(st->seconds_per_day); + Py_CLEAR(st->utc); + Py_CLEAR(st->epoch); + return 0; +} + static int _datetime_exec(PyObject *module) { @@ -6810,8 +6827,8 @@ _datetime_exec(PyObject *module) return -1; } - datetime_state *st = GLOBAL_STATE(); - st->utc = utc; + datetime_state *st = STATIC_STATE(); + Py_SETREF(st->utc, utc); /* bpo-37642: These attributes are rounded to the nearest minute for backwards * compatibility, even though the constructor will accept a wider range of @@ -6920,13 +6937,7 @@ _datetime_exec(PyObject *module) return 0; error: - Py_CLEAR(st->us_per_ms); - Py_CLEAR(st->us_per_second); - Py_CLEAR(st->us_per_minute); - Py_CLEAR(st->us_per_hour); - Py_CLEAR(st->us_per_day); - Py_CLEAR(st->us_per_week); - Py_CLEAR(st->seconds_per_day); + datetime_clear(module); return -1; } From 3ee48d295e8a36cd8f241b38b02dcff3e8c789bb Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 11 Oct 2023 16:07:41 +0200 Subject: [PATCH 13/15] Fix ref leak in init --- Modules/_datetimemodule.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 5c26ba51399f5d..c2eb6f16364e06 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6817,25 +6817,22 @@ _datetime_exec(PyObject *module) return -1; } - PyObject *utc = create_timezone(delta, NULL); + datetime_state *st = STATIC_STATE(); + st->utc = create_timezone(delta, NULL); Py_DECREF(delta); - if (utc == NULL) { - return -1; + if (st->utc == NULL) { + goto error; } - if (PyDict_SetItemString(d, "utc", utc) < 0) { - Py_DECREF(utc); - return -1; + if (PyDict_SetItemString(d, "utc", st->utc) < 0) { + goto error; } - datetime_state *st = STATIC_STATE(); - Py_SETREF(st->utc, utc); - /* bpo-37642: These attributes are rounded to the nearest minute for backwards * compatibility, even though the constructor will accept a wider range of * values. This may change in the future.*/ delta = new_delta(-1, 60, 0, 1); /* -23:59 */ if (delta == NULL) { - return -1; + goto error; } PyObject *x = create_timezone(delta, NULL); @@ -6844,7 +6841,7 @@ _datetime_exec(PyObject *module) delta = new_delta(0, (23 * 60 + 59) * 60, 0, 0); /* +23:59 */ if (delta == NULL) { - return -1; + goto error; } x = create_timezone(delta, NULL); @@ -6854,33 +6851,33 @@ _datetime_exec(PyObject *module) /* Epoch */ st->epoch = new_datetime(1970, 1, 1, 0, 0, 0, 0, st->utc, 0); if (st->epoch == NULL) { - return -1; + goto error; } /* module initialization */ if (PyModule_AddIntMacro(module, MINYEAR) < 0) { - return -1; + goto error; } if (PyModule_AddIntMacro(module, MAXYEAR) < 0) { - return -1; + goto error; } PyDateTime_CAPI *capi = get_datetime_capi(); if (capi == NULL) { - return -1; + goto error; } x = PyCapsule_New(capi, PyDateTime_CAPSULE_NAME, datetime_destructor); if (x == NULL) { PyMem_Free(capi); - return -1; + goto error; } if (PyModule_Add(module, "datetime_CAPI", x) < 0) { - return -1; + goto error; } if (PyModule_AddObjectRef(module, "UTC", st->utc) < 0) { - return -1; + goto error; } /* A 4-year cycle has an extra leap day over what we'd get from From a9e8d1ab544add7db66e85f31e9dfe9afd736474 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 11 Oct 2023 22:05:26 +0200 Subject: [PATCH 14/15] Clean up initialisation --- Modules/_datetimemodule.c | 164 ++++++++++++++++++++------------------ 1 file changed, 87 insertions(+), 77 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index c2eb6f16364e06..4e591c368232e7 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6741,6 +6741,68 @@ datetime_clear(PyObject *module) return 0; } +static PyObject * +create_timezone_from_delta(int days, int sec, int ms, int normalize) +{ + PyObject *delta = new_delta(days, sec, ms, normalize); + if (delta == NULL) { + return NULL; + } + PyObject *tz = create_timezone(delta, NULL); + Py_DECREF(delta); + return tz; +} + +static int +init_state(datetime_state *st) +{ + st->us_per_ms = PyLong_FromLong(1000); + if (st->us_per_ms == NULL) { + return -1; + } + st->us_per_second = PyLong_FromLong(1000000); + if (st->us_per_second == NULL) { + return -1; + } + st->us_per_minute = PyLong_FromLong(60000000); + if (st->us_per_minute == NULL) { + return -1; + } + st->seconds_per_day = PyLong_FromLong(24 * 3600); + if (st->seconds_per_day == NULL) { + return -1; + } + + /* The rest are too big for 32-bit ints, but even + * us_per_week fits in 40 bits, so doubles should be exact. + */ + st->us_per_hour = PyLong_FromDouble(3600000000.0); + if (st->us_per_hour == NULL) { + return -1; + } + st->us_per_day = PyLong_FromDouble(86400000000.0); + if (st->us_per_day == NULL) { + return -1; + } + st->us_per_week = PyLong_FromDouble(604800000000.0); + if (st->us_per_week == NULL) { + return -1; + } + + /* Init UTC timezone */ + st->utc = create_timezone_from_delta(0, 0, 0, 0); + if (st->utc == NULL) { + return -1; + } + + /* Init Unix epoch */ + st->epoch = new_datetime(1970, 1, 1, 0, 0, 0, 0, st->utc, 0); + if (st->epoch == NULL) { + return -1; + } + return 0; +} + static int _datetime_exec(PyObject *module) { @@ -6762,23 +6824,23 @@ _datetime_exec(PyObject *module) for (size_t i = 0; i < Py_ARRAY_LENGTH(types); i++) { if (PyModule_AddType(module, types[i]) < 0) { - return -1; + goto error; } } if (PyType_Ready(&PyDateTime_IsoCalendarDateType) < 0) { - return -1; + goto error; } #define DATETIME_ADD_MACRO(dict, c, value_expr) \ do { \ PyObject *value = (value_expr); \ if (value == NULL) { \ - return -1; \ + goto error; \ } \ if (PyDict_SetItemString(dict, c, value) < 0) { \ Py_DECREF(value); \ - return -1; \ + goto error; \ } \ Py_DECREF(value); \ } while(0) @@ -6810,19 +6872,13 @@ _datetime_exec(PyObject *module) 999999, Py_None, 0)); DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0)); - /* timezone values */ - d = PyDateTime_TimeZoneType.tp_dict; - PyObject *delta = new_delta(0, 0, 0, 0); - if (delta == NULL) { - return -1; - } - datetime_state *st = STATIC_STATE(); - st->utc = create_timezone(delta, NULL); - Py_DECREF(delta); - if (st->utc == NULL) { + if (init_state(st) < 0) { goto error; } + + /* timezone values */ + d = PyDateTime_TimeZoneType.tp_dict; if (PyDict_SetItemString(d, "utc", st->utc) < 0) { goto error; } @@ -6830,53 +6886,39 @@ _datetime_exec(PyObject *module) /* bpo-37642: These attributes are rounded to the nearest minute for backwards * compatibility, even though the constructor will accept a wider range of * values. This may change in the future.*/ - delta = new_delta(-1, 60, 0, 1); /* -23:59 */ - if (delta == NULL) { - goto error; - } - - PyObject *x = create_timezone(delta, NULL); - Py_DECREF(delta); - DATETIME_ADD_MACRO(d, "min", x); - delta = new_delta(0, (23 * 60 + 59) * 60, 0, 0); /* +23:59 */ - if (delta == NULL) { - goto error; - } + /* -23:59 */ + PyObject *min = create_timezone_from_delta(-1, 60, 0, 1); + DATETIME_ADD_MACRO(d, "min", min); - x = create_timezone(delta, NULL); - Py_DECREF(delta); - DATETIME_ADD_MACRO(d, "max", x); + /* 23:59 */ + PyObject *max = create_timezone_from_delta(0, (23 * 60 + 59) * 60, 0, 0); + DATETIME_ADD_MACRO(d, "max", max); - /* Epoch */ - st->epoch = new_datetime(1970, 1, 1, 0, 0, 0, 0, st->utc, 0); - if (st->epoch == NULL) { - goto error; - } - - /* module initialization */ + /* Add module level attributes */ if (PyModule_AddIntMacro(module, MINYEAR) < 0) { goto error; } if (PyModule_AddIntMacro(module, MAXYEAR) < 0) { goto error; } + if (PyModule_AddObjectRef(module, "UTC", st->utc) < 0) { + goto error; + } + /* At last, set up and add the encapsulated C API */ PyDateTime_CAPI *capi = get_datetime_capi(); if (capi == NULL) { goto error; } - x = PyCapsule_New(capi, PyDateTime_CAPSULE_NAME, datetime_destructor); - if (x == NULL) { + PyObject *capsule = PyCapsule_New(capi, PyDateTime_CAPSULE_NAME, + datetime_destructor); + if (capsule == NULL) { PyMem_Free(capi); goto error; } - - if (PyModule_Add(module, "datetime_CAPI", x) < 0) { - goto error; - } - - if (PyModule_AddObjectRef(module, "UTC", st->utc) < 0) { + if (PyModule_Add(module, "datetime_CAPI", capsule) < 0) { + PyMem_Free(capi); goto error; } @@ -6898,45 +6940,13 @@ _datetime_exec(PyObject *module) static_assert(DI100Y == 25 * DI4Y - 1, "DI100Y"); assert(DI100Y == days_before_year(100+1)); - st->us_per_ms = PyLong_FromLong(1000); - if (st->us_per_ms == NULL) { - goto error; - } - st->us_per_second = PyLong_FromLong(1000000); - if (st->us_per_second == NULL) { - goto error; - } - st->us_per_minute = PyLong_FromLong(60000000); - if (st->us_per_minute == NULL) { - goto error; - } - st->seconds_per_day = PyLong_FromLong(24 * 3600); - if (st->seconds_per_day == NULL) { - goto error; - } - - /* The rest are too big for 32-bit ints, but even - * us_per_week fits in 40 bits, so doubles should be exact. - */ - st->us_per_hour = PyLong_FromDouble(3600000000.0); - if (st->us_per_hour == NULL) { - goto error; - } - st->us_per_day = PyLong_FromDouble(86400000000.0); - if (st->us_per_day == NULL) { - goto error; - } - st->us_per_week = PyLong_FromDouble(604800000000.0); - if (st->us_per_week == NULL) { - goto error; - } - return 0; error: datetime_clear(module); return -1; } +#undef DATETIME_ADD_MACRO static struct PyModuleDef datetimemodule = { .m_base = PyModuleDef_HEAD_INIT, From c3ba7fec5b5fa5d46d0af8f99a5ffd421d01de65 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 11 Oct 2023 22:12:11 +0200 Subject: [PATCH 15/15] Preserve comment --- Modules/_datetimemodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 4e591c368232e7..684a628806fbb5 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6891,7 +6891,7 @@ _datetime_exec(PyObject *module) PyObject *min = create_timezone_from_delta(-1, 60, 0, 1); DATETIME_ADD_MACRO(d, "min", min); - /* 23:59 */ + /* +23:59 */ PyObject *max = create_timezone_from_delta(0, (23 * 60 + 59) * 60, 0, 0); DATETIME_ADD_MACRO(d, "max", max);