Skip to content

Commit e55b05f

Browse files
authored
GH-121832: Assert that the version number of static builtin types is not changed by PyType_Modified. (GH-122182)
Update datetime module and test_type_cache.py to not call PyType_Modified.
1 parent b3b7b7d commit e55b05f

File tree

3 files changed

+46
-67
lines changed

3 files changed

+46
-67
lines changed

Lib/test/test_type_cache.py

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -161,34 +161,15 @@ def load_foo_2(type_):
161161
self._check_specialization(load_foo_2, A, "LOAD_ATTR", should_specialize=False)
162162

163163
def test_class_load_attr_specialization_static_type(self):
164-
self._assign_valid_version_or_skip(str)
165-
self._assign_valid_version_or_skip(bytes)
164+
self.assertNotEqual(type_get_version(str), 0)
165+
self.assertNotEqual(type_get_version(bytes), 0)
166166

167167
def get_capitalize_1(type_):
168168
return type_.capitalize
169169

170170
self._check_specialization(get_capitalize_1, str, "LOAD_ATTR", should_specialize=True)
171171
self.assertEqual(get_capitalize_1(str)('hello'), 'Hello')
172172
self.assertEqual(get_capitalize_1(bytes)(b'hello'), b'Hello')
173-
del get_capitalize_1
174-
175-
# Permanently overflow the static type version counter, and force str and bytes
176-
# to have tp_version_tag == 0
177-
for _ in range(2**16):
178-
type_modified(str)
179-
type_assign_version(str)
180-
type_modified(bytes)
181-
type_assign_version(bytes)
182-
183-
self.assertEqual(type_get_version(str), 0)
184-
self.assertEqual(type_get_version(bytes), 0)
185-
186-
def get_capitalize_2(type_):
187-
return type_.capitalize
188-
189-
self._check_specialization(get_capitalize_2, str, "LOAD_ATTR", should_specialize=False)
190-
self.assertEqual(get_capitalize_2(str)('hello'), 'Hello')
191-
self.assertEqual(get_capitalize_2(bytes)(b'hello'), b'Hello')
192173

193174
def test_property_load_attr_specialization_user_type(self):
194175
class G:

Modules/_datetimemodule.c

Lines changed: 42 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -7256,49 +7256,51 @@ _datetime_exec(PyObject *module)
72567256
Py_DECREF(value); \
72577257
} while(0)
72587258

7259-
/* timedelta values */
7260-
PyObject *d = _PyType_GetDict(&PyDateTime_DeltaType);
7261-
DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
7262-
DATETIME_ADD_MACRO(d, "min", new_delta(-MAX_DELTA_DAYS, 0, 0, 0));
7263-
DATETIME_ADD_MACRO(d, "max",
7264-
new_delta(MAX_DELTA_DAYS, 24*3600-1, 1000000-1, 0));
7265-
7266-
/* date values */
7267-
d = _PyType_GetDict(&PyDateTime_DateType);
7268-
DATETIME_ADD_MACRO(d, "min", new_date(1, 1, 1));
7269-
DATETIME_ADD_MACRO(d, "max", new_date(MAXYEAR, 12, 31));
7270-
DATETIME_ADD_MACRO(d, "resolution", new_delta(1, 0, 0, 0));
7271-
7272-
/* time values */
7273-
d = _PyType_GetDict(&PyDateTime_TimeType);
7274-
DATETIME_ADD_MACRO(d, "min", new_time(0, 0, 0, 0, Py_None, 0));
7275-
DATETIME_ADD_MACRO(d, "max", new_time(23, 59, 59, 999999, Py_None, 0));
7276-
DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
7277-
7278-
/* datetime values */
7279-
d = _PyType_GetDict(&PyDateTime_DateTimeType);
7280-
DATETIME_ADD_MACRO(d, "min",
7281-
new_datetime(1, 1, 1, 0, 0, 0, 0, Py_None, 0));
7282-
DATETIME_ADD_MACRO(d, "max", new_datetime(MAXYEAR, 12, 31, 23, 59, 59,
7283-
999999, Py_None, 0));
7284-
DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
7285-
7286-
/* timezone values */
7287-
d = _PyType_GetDict(&PyDateTime_TimeZoneType);
7288-
if (PyDict_SetItemString(d, "utc", (PyObject *)&utc_timezone) < 0) {
7289-
goto error;
7290-
}
7259+
if (!reloading) {
7260+
/* timedelta values */
7261+
PyObject *d = _PyType_GetDict(&PyDateTime_DeltaType);
7262+
DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
7263+
DATETIME_ADD_MACRO(d, "min", new_delta(-MAX_DELTA_DAYS, 0, 0, 0));
7264+
DATETIME_ADD_MACRO(d, "max",
7265+
new_delta(MAX_DELTA_DAYS, 24*3600-1, 1000000-1, 0));
7266+
7267+
/* date values */
7268+
d = _PyType_GetDict(&PyDateTime_DateType);
7269+
DATETIME_ADD_MACRO(d, "min", new_date(1, 1, 1));
7270+
DATETIME_ADD_MACRO(d, "max", new_date(MAXYEAR, 12, 31));
7271+
DATETIME_ADD_MACRO(d, "resolution", new_delta(1, 0, 0, 0));
7272+
7273+
/* time values */
7274+
d = _PyType_GetDict(&PyDateTime_TimeType);
7275+
DATETIME_ADD_MACRO(d, "min", new_time(0, 0, 0, 0, Py_None, 0));
7276+
DATETIME_ADD_MACRO(d, "max", new_time(23, 59, 59, 999999, Py_None, 0));
7277+
DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
7278+
7279+
/* datetime values */
7280+
d = _PyType_GetDict(&PyDateTime_DateTimeType);
7281+
DATETIME_ADD_MACRO(d, "min",
7282+
new_datetime(1, 1, 1, 0, 0, 0, 0, Py_None, 0));
7283+
DATETIME_ADD_MACRO(d, "max", new_datetime(MAXYEAR, 12, 31, 23, 59, 59,
7284+
999999, Py_None, 0));
7285+
DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
7286+
7287+
/* timezone values */
7288+
d = _PyType_GetDict(&PyDateTime_TimeZoneType);
7289+
if (PyDict_SetItemString(d, "utc", (PyObject *)&utc_timezone) < 0) {
7290+
goto error;
7291+
}
72917292

7292-
/* bpo-37642: These attributes are rounded to the nearest minute for backwards
7293-
* compatibility, even though the constructor will accept a wider range of
7294-
* values. This may change in the future.*/
7293+
/* bpo-37642: These attributes are rounded to the nearest minute for backwards
7294+
* compatibility, even though the constructor will accept a wider range of
7295+
* values. This may change in the future.*/
72957296

7296-
/* -23:59 */
7297-
DATETIME_ADD_MACRO(d, "min", create_timezone_from_delta(-1, 60, 0, 1));
7297+
/* -23:59 */
7298+
DATETIME_ADD_MACRO(d, "min", create_timezone_from_delta(-1, 60, 0, 1));
72987299

7299-
/* +23:59 */
7300-
DATETIME_ADD_MACRO(
7301-
d, "max", create_timezone_from_delta(0, (23 * 60 + 59) * 60, 0, 0));
7300+
/* +23:59 */
7301+
DATETIME_ADD_MACRO(
7302+
d, "max", create_timezone_from_delta(0, (23 * 60 + 59) * 60, 0, 0));
7303+
}
73027304

73037305
#undef DATETIME_ADD_MACRO
73047306

@@ -7342,12 +7344,6 @@ _datetime_exec(PyObject *module)
73427344
static_assert(DI100Y == 25 * DI4Y - 1, "DI100Y");
73437345
assert(DI100Y == days_before_year(100+1));
73447346

7345-
if (reloading) {
7346-
for (size_t i = 0; i < Py_ARRAY_LENGTH(capi_types); i++) {
7347-
PyType_Modified(capi_types[i]);
7348-
}
7349-
}
7350-
73517347
if (set_current_module(interp, module) < 0) {
73527348
goto error;
73537349
}

Objects/typeobject.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,8 @@ type_modified_unlocked(PyTypeObject *type)
10261026
if (type->tp_version_tag == 0) {
10271027
return;
10281028
}
1029+
// Cannot modify static builtin types.
1030+
assert((type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) == 0);
10291031

10301032
PyObject *subclasses = lookup_tp_subclasses(type);
10311033
if (subclasses != NULL) {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy