]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-71587: Drop local reference cache to `_strptime` module in `_datetime`...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Wed, 12 Jun 2024 17:15:16 +0000 (19:15 +0200)
committerGitHub <noreply@github.com>
Wed, 12 Jun 2024 17:15:16 +0000 (17:15 +0000)
The _strptime module object was cached in a static local variable (in the datetime.strptime() implementation).  That's a problem when it crosses isolation boundaries, such as reinitializing the runtme or between interpreters.  This change fixes the problem by dropping the static variable, instead always relying on the normal sys.modules cache (via PyImport_Import()).

(cherry picked from commit 127c1d2771749853e287632c086b6054212bf12a, AKA gh-120224)

Co-authored-by: neonene <53406459+neonene@users.noreply.github.com>
Include/internal/pycore_global_objects_fini_generated.h
Include/internal/pycore_global_strings.h
Include/internal/pycore_runtime_init_generated.h
Include/internal/pycore_unicodeobject_generated.h
Lib/test/test_embed.py
Misc/NEWS.d/next/Library/2024-06-07-11-23-31.gh-issue-71587.IjFajE.rst [new file with mode: 0644]
Modules/_datetimemodule.c
Tools/c-analyzer/cpython/globals-to-fix.tsv

index a40f007bdacc431dffdfa6245d3b6cf47624fee5..07d96bab707b7b49e6c58e6505f37bfcca5b0498 100644 (file)
@@ -776,6 +776,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_showwarnmsg));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_shutdown));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_slotnames));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_strptime));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_strptime_datetime));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_swappedbytes_));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_type_));
index eaf81e4f115159cfcc17f1c1942a21f47c0e824b..9b2becdb1323cd56cf5d38a547db287c67e9624b 100644 (file)
@@ -265,6 +265,7 @@ struct _Py_global_strings {
         STRUCT_FOR_ID(_showwarnmsg)
         STRUCT_FOR_ID(_shutdown)
         STRUCT_FOR_ID(_slotnames)
+        STRUCT_FOR_ID(_strptime)
         STRUCT_FOR_ID(_strptime_datetime)
         STRUCT_FOR_ID(_swappedbytes_)
         STRUCT_FOR_ID(_type_)
index b18c2684691ce26f2f5dd8c14ba17b719242fa9e..6a38b2085c492d874052156ae9f53c39f61ef64f 100644 (file)
@@ -774,6 +774,7 @@ extern "C" {
     INIT_ID(_showwarnmsg), \
     INIT_ID(_shutdown), \
     INIT_ID(_slotnames), \
+    INIT_ID(_strptime), \
     INIT_ID(_strptime_datetime), \
     INIT_ID(_swappedbytes_), \
     INIT_ID(_type_), \
index 87e22ac39c1fef76b136480cb166c250ff5435f2..16502bb4deaad1a108a1c192773077819aa8a890 100644 (file)
@@ -636,6 +636,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
     string = &_Py_ID(_slotnames);
     assert(_PyUnicode_CheckConsistency(string, 1));
     _PyUnicode_InternInPlace(interp, &string);
+    string = &_Py_ID(_strptime);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    _PyUnicode_InternInPlace(interp, &string);
     string = &_Py_ID(_strptime_datetime);
     assert(_PyUnicode_CheckConsistency(string, 1));
     _PyUnicode_InternInPlace(interp, &string);
index d94c63a13b8ea40d177a3eda10ed162ed7e01f2f..634513ec7a58120b08cee1432e4233e11d7f446c 100644 (file)
@@ -404,6 +404,15 @@ class EmbeddingTests(EmbeddingTestsMixin, unittest.TestCase):
         out, err = self.run_embedded_interpreter("test_repeated_init_exec", code)
         self.assertEqual(out, '9\n' * INIT_LOOPS)
 
+    def test_datetime_reset_strptime(self):
+        code = (
+            "import datetime;"
+            "d = datetime.datetime.strptime('2000-01-01', '%Y-%m-%d');"
+            "print(d.strftime('%Y%m%d'))"
+        )
+        out, err = self.run_embedded_interpreter("test_repeated_init_exec", code)
+        self.assertEqual(out, '20000101\n' * INIT_LOOPS)
+
 
 @unittest.skipIf(_testinternalcapi is None, "requires _testinternalcapi")
 class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
diff --git a/Misc/NEWS.d/next/Library/2024-06-07-11-23-31.gh-issue-71587.IjFajE.rst b/Misc/NEWS.d/next/Library/2024-06-07-11-23-31.gh-issue-71587.IjFajE.rst
new file mode 100644 (file)
index 0000000..50a6629
--- /dev/null
@@ -0,0 +1,2 @@
+Fix crash in C version of :meth:`datetime.datetime.strptime` when called again
+on the restarted interpreter.
index d6fa273c75e15ebbee96999ecfee99c97744e2ab..7db303032362eb5052a388e5ff39226bbc55a956 100644 (file)
@@ -5511,19 +5511,19 @@ datetime_utcfromtimestamp(PyObject *cls, PyObject *args)
 static PyObject *
 datetime_strptime(PyObject *cls, PyObject *args)
 {
-    static PyObject *module = NULL;
-    PyObject *string, *format;
+    PyObject *string, *format, *result;
 
     if (!PyArg_ParseTuple(args, "UU:strptime", &string, &format))
         return NULL;
 
+    PyObject *module = PyImport_Import(&_Py_ID(_strptime));
     if (module == NULL) {
-        module = PyImport_ImportModule("_strptime");
-        if (module == NULL)
-            return NULL;
+        return NULL;
     }
-    return PyObject_CallMethodObjArgs(module, &_Py_ID(_strptime_datetime),
-                                         cls, string, format, NULL);
+    result = PyObject_CallMethodObjArgs(module, &_Py_ID(_strptime_datetime),
+                                        cls, string, format, NULL);
+    Py_DECREF(module);
+    return result;
 }
 
 /* Return new datetime from date/datetime and time arguments. */
index aeb7cad9e027c025c7f73aaea948d611662be97b..06e58e92184efa93ee87c2cd380d805f33302f17 100644 (file)
@@ -434,7 +434,6 @@ Modules/_ctypes/_ctypes.c   CreateSwappedType       swapped_suffix  -
 Modules/_ctypes/_ctypes.c      -       _unpickle       -
 Modules/_ctypes/_ctypes.c      PyCArrayType_from_ctype array_cache     -
 Modules/_cursesmodule.c        -       ModDict -
-Modules/_datetimemodule.c      datetime_strptime       module  -
 
 ## state
 Modules/_ctypes/_ctypes.c      -       _ctypes_ptrtype_cache   -