]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-71587: Drop local reference cache to `_strptime` module in `_datetime` (gh-120224)
authorneonene <53406459+neonene@users.noreply.github.com>
Wed, 12 Jun 2024 16:46:39 +0000 (01:46 +0900)
committerGitHub <noreply@github.com>
Wed, 12 Jun 2024 16:46:39 +0000 (10:46 -0600)
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()).

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 30851dc2dbec449f4b5d29062f022ba75601fdd1..bc94930b85f09887e6c800f498b4612bf9dce4b3 100644 (file)
@@ -777,6 +777,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 009802c441685c67bc684bbaf23fc5db25d02bc0..998be2ec490dd9dbe27b974668eca95699ef7911 100644 (file)
@@ -266,6 +266,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 ff5b6ee8e0f006084d5328570ff0910764236776..bd79a7dff42f895de5c58985d567b65ccbdd3970 100644 (file)
@@ -775,6 +775,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 69d93a9610a2e55054f6da2137b86132f6f5d2c4..7284aeb592d7ec6727cee60e0ae5c7dc620e7e58 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 bea6e9411a75edaba238e83df59a52e44ce819b6..cb4622893375d75605967f9811ca1d776182eb17 100644 (file)
@@ -5514,19 +5514,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 4586a59f6ac2efebeebc6fdd8fcf7eb35905bcad..cb9750a69a632b0d0a8363aa45969813be93066d 100644 (file)
@@ -393,7 +393,6 @@ Modules/xxmodule.c  -       ErrorObject     -
 
 ## initialized once
 Modules/_cursesmodule.c        -       ModDict -
-Modules/_datetimemodule.c      datetime_strptime       module  -
 
 ## state
 Modules/_datetimemodule.c      -       _datetime_global_state  -