Skip to content

Commit

Permalink
[3.13] GH-121832: Assert that the version number of static builtin ty…
Browse files Browse the repository at this point in the history
…pes 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 <mark@hotpy.org>
  • Loading branch information
miss-islington and markshannon authored Jul 25, 2024
1 parent dd270f6 commit aca41cf
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 67 deletions.
23 changes: 2 additions & 21 deletions Lib/test/test_type_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,34 +160,15 @@ def load_foo_2(type_):
self._check_specialization(load_foo_2, A, "LOAD_ATTR", should_specialize=False)

def test_class_load_attr_specialization_static_type(self):
self._assign_valid_version_or_skip(str)
self._assign_valid_version_or_skip(bytes)
self.assertNotEqual(type_get_version(str), 0)
self.assertNotEqual(type_get_version(bytes), 0)

def get_capitalize_1(type_):
return type_.capitalize

self._check_specialization(get_capitalize_1, str, "LOAD_ATTR", should_specialize=True)
self.assertEqual(get_capitalize_1(str)('hello'), 'Hello')
self.assertEqual(get_capitalize_1(bytes)(b'hello'), b'Hello')
del get_capitalize_1

# Permanently overflow the static type version counter, and force str and bytes
# to have tp_version_tag == 0
for _ in range(2**16):
type_modified(str)
type_assign_version(str)
type_modified(bytes)
type_assign_version(bytes)

self.assertEqual(type_get_version(str), 0)
self.assertEqual(type_get_version(bytes), 0)

def get_capitalize_2(type_):
return type_.capitalize

self._check_specialization(get_capitalize_2, str, "LOAD_ATTR", should_specialize=False)
self.assertEqual(get_capitalize_2(str)('hello'), 'Hello')
self.assertEqual(get_capitalize_2(bytes)(b'hello'), b'Hello')

def test_property_load_attr_specialization_user_type(self):
class G:
Expand Down
88 changes: 42 additions & 46 deletions Modules/_datetimemodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -7253,49 +7253,51 @@ _datetime_exec(PyObject *module)
Py_DECREF(value); \
} while(0)

/* timedelta values */
PyObject *d = _PyType_GetDict(&PyDateTime_DeltaType);
DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
DATETIME_ADD_MACRO(d, "min", new_delta(-MAX_DELTA_DAYS, 0, 0, 0));
DATETIME_ADD_MACRO(d, "max",
new_delta(MAX_DELTA_DAYS, 24*3600-1, 1000000-1, 0));

/* date values */
d = _PyType_GetDict(&PyDateTime_DateType);
DATETIME_ADD_MACRO(d, "min", new_date(1, 1, 1));
DATETIME_ADD_MACRO(d, "max", new_date(MAXYEAR, 12, 31));
DATETIME_ADD_MACRO(d, "resolution", new_delta(1, 0, 0, 0));

/* time values */
d = _PyType_GetDict(&PyDateTime_TimeType);
DATETIME_ADD_MACRO(d, "min", new_time(0, 0, 0, 0, Py_None, 0));
DATETIME_ADD_MACRO(d, "max", new_time(23, 59, 59, 999999, Py_None, 0));
DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));

/* datetime values */
d = _PyType_GetDict(&PyDateTime_DateTimeType);
DATETIME_ADD_MACRO(d, "min",
new_datetime(1, 1, 1, 0, 0, 0, 0, Py_None, 0));
DATETIME_ADD_MACRO(d, "max", new_datetime(MAXYEAR, 12, 31, 23, 59, 59,
999999, Py_None, 0));
DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));

/* timezone values */
d = _PyType_GetDict(&PyDateTime_TimeZoneType);
if (PyDict_SetItemString(d, "utc", (PyObject *)&utc_timezone) < 0) {
goto error;
}
if (!reloading) {
/* timedelta values */
PyObject *d = _PyType_GetDict(&PyDateTime_DeltaType);
DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
DATETIME_ADD_MACRO(d, "min", new_delta(-MAX_DELTA_DAYS, 0, 0, 0));
DATETIME_ADD_MACRO(d, "max",
new_delta(MAX_DELTA_DAYS, 24*3600-1, 1000000-1, 0));

/* date values */
d = _PyType_GetDict(&PyDateTime_DateType);
DATETIME_ADD_MACRO(d, "min", new_date(1, 1, 1));
DATETIME_ADD_MACRO(d, "max", new_date(MAXYEAR, 12, 31));
DATETIME_ADD_MACRO(d, "resolution", new_delta(1, 0, 0, 0));

/* time values */
d = _PyType_GetDict(&PyDateTime_TimeType);
DATETIME_ADD_MACRO(d, "min", new_time(0, 0, 0, 0, Py_None, 0));
DATETIME_ADD_MACRO(d, "max", new_time(23, 59, 59, 999999, Py_None, 0));
DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));

/* datetime values */
d = _PyType_GetDict(&PyDateTime_DateTimeType);
DATETIME_ADD_MACRO(d, "min",
new_datetime(1, 1, 1, 0, 0, 0, 0, Py_None, 0));
DATETIME_ADD_MACRO(d, "max", new_datetime(MAXYEAR, 12, 31, 23, 59, 59,
999999, Py_None, 0));
DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));

/* timezone values */
d = _PyType_GetDict(&PyDateTime_TimeZoneType);
if (PyDict_SetItemString(d, "utc", (PyObject *)&utc_timezone) < 0) {
goto error;
}

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

/* -23:59 */
DATETIME_ADD_MACRO(d, "min", create_timezone_from_delta(-1, 60, 0, 1));
/* -23:59 */
DATETIME_ADD_MACRO(d, "min", create_timezone_from_delta(-1, 60, 0, 1));

/* +23:59 */
DATETIME_ADD_MACRO(
d, "max", create_timezone_from_delta(0, (23 * 60 + 59) * 60, 0, 0));
/* +23:59 */
DATETIME_ADD_MACRO(
d, "max", create_timezone_from_delta(0, (23 * 60 + 59) * 60, 0, 0));
}

#undef DATETIME_ADD_MACRO

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

if (reloading) {
for (size_t i = 0; i < Py_ARRAY_LENGTH(capi_types); i++) {
PyType_Modified(capi_types[i]);
}
}

if (set_current_module(interp, module) < 0) {
goto error;
}
Expand Down
2 changes: 2 additions & 0 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -999,6 +999,8 @@ type_modified_unlocked(PyTypeObject *type)
if (type->tp_version_tag == 0) {
return;
}
// Cannot modify static builtin types.
assert((type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) == 0);

PyObject *subclasses = lookup_tp_subclasses(type);
if (subclasses != NULL) {
Expand Down

0 comments on commit aca41cf

Please sign in to comment.