Skip to content

Commit aca41cf

Browse files
[3.13] GH-121832: Assert that the version number of static builtin types is not changed by PyType_Modified (gh-122290)
Update datetime module and test_type_cache.py to not call PyType_Modified. (cherry picked from commit e55b05f, AKA gh--122182) Co-authored-by: Mark Shannon <[email protected]>
1 parent dd270f6 commit aca41cf

File tree

3 files changed

+46
-67
lines changed

3 files changed

+46
-67
lines changed

Diff for: Lib/test/test_type_cache.py

+2-21
Original file line numberDiff line numberDiff line change
@@ -160,34 +160,15 @@ def load_foo_2(type_):
160160
self._check_specialization(load_foo_2, A, "LOAD_ATTR", should_specialize=False)
161161

162162
def test_class_load_attr_specialization_static_type(self):
163-
self._assign_valid_version_or_skip(str)
164-
self._assign_valid_version_or_skip(bytes)
163+
self.assertNotEqual(type_get_version(str), 0)
164+
self.assertNotEqual(type_get_version(bytes), 0)
165165

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

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

192173
def test_property_load_attr_specialization_user_type(self):
193174
class G:

Diff for: Modules/_datetimemodule.c

+42-46
Original file line numberDiff line numberDiff line change
@@ -7253,49 +7253,51 @@ _datetime_exec(PyObject *module)
72537253
Py_DECREF(value); \
72547254
} while(0)
72557255

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

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

7293-
/* -23:59 */
7294-
DATETIME_ADD_MACRO(d, "min", create_timezone_from_delta(-1, 60, 0, 1));
7294+
/* -23:59 */
7295+
DATETIME_ADD_MACRO(d, "min", create_timezone_from_delta(-1, 60, 0, 1));
72957296

7296-
/* +23:59 */
7297-
DATETIME_ADD_MACRO(
7298-
d, "max", create_timezone_from_delta(0, (23 * 60 + 59) * 60, 0, 0));
7297+
/* +23:59 */
7298+
DATETIME_ADD_MACRO(
7299+
d, "max", create_timezone_from_delta(0, (23 * 60 + 59) * 60, 0, 0));
7300+
}
72997301

73007302
#undef DATETIME_ADD_MACRO
73017303

@@ -7339,12 +7341,6 @@ _datetime_exec(PyObject *module)
73397341
static_assert(DI100Y == 25 * DI4Y - 1, "DI100Y");
73407342
assert(DI100Y == days_before_year(100+1));
73417343

7342-
if (reloading) {
7343-
for (size_t i = 0; i < Py_ARRAY_LENGTH(capi_types); i++) {
7344-
PyType_Modified(capi_types[i]);
7345-
}
7346-
}
7347-
73487344
if (set_current_module(interp, module) < 0) {
73497345
goto error;
73507346
}

Diff for: Objects/typeobject.c

+2
Original file line numberDiff line numberDiff line change
@@ -999,6 +999,8 @@ type_modified_unlocked(PyTypeObject *type)
999999
if (type->tp_version_tag == 0) {
10001000
return;
10011001
}
1002+
// Cannot modify static builtin types.
1003+
assert((type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) == 0);
10021004

10031005
PyObject *subclasses = lookup_tp_subclasses(type);
10041006
if (subclasses != NULL) {

0 commit comments

Comments
 (0)