Skip to content

Commit 1c01521

Browse files
committed
gh-142781: address review comments by refactoring TypeError message, rewriting NEWS and improving unit test
1 parent bf06241 commit 1c01521

File tree

3 files changed

+24
-23
lines changed

3 files changed

+24
-23
lines changed

Lib/test/test_zoneinfo/test_zoneinfo.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1575,33 +1575,37 @@ class EvilZoneInfo(self.klass):
15751575
class CZoneInfoCacheTest(ZoneInfoCacheTest):
15761576
module = c_zoneinfo
15771577

1578-
def test_weak_cache_get_type_confusion(self):
1579-
class EvilCache:
1578+
def test_inconsistent_weak_cache_get(self):
1579+
class Cache:
15801580
def get(self, key, default=None):
15811581
return 1337
15821582

1583-
class EvilZoneInfo(self.klass):
1583+
class ZI(self.klass):
15841584
pass
1585+
# Must set AFTER class creation to override __init_subclass__
1586+
ZI._weak_cache = Cache()
15851587

1586-
EvilZoneInfo._weak_cache = EvilCache()
1587-
1588-
with self.assertRaises(TypeError):
1589-
EvilZoneInfo("America/Los_Angeles")
1588+
with self.assertRaises(TypeError) as te:
1589+
ZI("America/Los_Angeles")
1590+
# Heap type objects' tp_name should just be the type name, i.e. ZI
1591+
self.assertEqual(str(te.exception), "expected ZI, got int")
15901592

1591-
def test_weak_cache_setdefault_type_confusion(self):
1592-
class EvilCache:
1593+
def test_inconsistent_weak_cache_setdefault(self):
1594+
class Cache:
15931595
def get(self, key, default=None):
15941596
return default
15951597
def setdefault(self, key, value):
15961598
return 1337
15971599

1598-
class EvilZoneInfo(self.klass):
1600+
class ZI(self.klass):
15991601
pass
1602+
# Must set AFTER class creation to override __init_subclass__
1603+
ZI._weak_cache = Cache()
16001604

1601-
EvilZoneInfo._weak_cache = EvilCache()
1602-
1603-
with self.assertRaises(TypeError):
1604-
EvilZoneInfo("America/Los_Angeles")
1605+
with self.assertRaises(TypeError) as te:
1606+
ZI("America/Los_Angeles")
1607+
# Heap type objects' tp_name should just be the type name, i.e. ZI
1608+
self.assertEqual(str(te.exception), "expected ZI, got int")
16051609

16061610
class ZoneInfoPickleTest(TzPathUserMixin, ZoneInfoTestBase):
16071611
module = py_zoneinfo
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
1-
Fix a type confusion in zoneinfo where a malicious override of _weak_cache
2-
in a zoneinfo subclass can cause memory corruption and crash the
3-
interpreter.
1+
:mod:`zoneinfo`: fix a crash when instantiating :class:`~zoneinfo.ZoneInfo`
2+
objects for which the internal class-level cache is inconsistent.

Modules/_zoneinfo.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -328,9 +328,8 @@ zoneinfo_ZoneInfo_impl(PyTypeObject *type, PyObject *key)
328328
}
329329

330330
if (instance != Py_None && !PyObject_TypeCheck(instance, type)) {
331-
const char *e = "%s._weak_cache.get() returned %s, expected %s";
332-
PyErr_Format(PyExc_TypeError, e,
333-
type->tp_name, Py_TYPE(instance)->tp_name, type->tp_name);
331+
PyErr_Format(PyExc_TypeError, "expected %s, got %s",
332+
type->tp_name, Py_TYPE(instance)->tp_name);
334333
Py_DECREF(instance);
335334
Py_DECREF(weak_cache);
336335
return NULL;
@@ -353,9 +352,8 @@ zoneinfo_ZoneInfo_impl(PyTypeObject *type, PyObject *key)
353352
}
354353

355354
if (!PyObject_TypeCheck(instance, type)) {
356-
const char *e = "%s._weak_cache.setdefault() returned %s, expected %s";
357-
PyErr_Format(PyExc_TypeError, e,
358-
type->tp_name, Py_TYPE(instance)->tp_name, type->tp_name);
355+
PyErr_Format(PyExc_TypeError, "expected %s, got %s",
356+
type->tp_name, Py_TYPE(instance)->tp_name);
359357
Py_DECREF(instance);
360358
Py_DECREF(weak_cache);
361359
return NULL;

0 commit comments

Comments
 (0)