Skip to content

Commit 838bcfb

Browse files
markshannonnohlson
authored andcommitted
pythonGH-121832: Assert that the version number of static builtin types is not changed by PyType_Modified. (pythonGH-122182)
Update datetime module and test_type_cache.py to not call PyType_Modified.
1 parent fa8bf4b commit 838bcfb

File tree

3 files changed

+46
-67
lines changed

3 files changed

+46
-67
lines changed

Lib/test/test_type_cache.py

+2-21
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

+42-46
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

+2
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)