Skip to content

Commit b611db4

Browse files
superboy-zjcpicnixzStanFromIreland
authored
pythongh-142781: Fix type confusion in zoneinfo weak cache (pythonGH-142925)
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com>
1 parent e542255 commit b611db4

File tree

3 files changed

+50
-1
lines changed

3 files changed

+50
-1
lines changed

Lib/test/test_zoneinfo/test_zoneinfo.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,6 +1577,44 @@ class EvilZoneInfo(self.klass):
15771577
class CZoneInfoCacheTest(ZoneInfoCacheTest):
15781578
module = c_zoneinfo
15791579

1580+
def test_inconsistent_weak_cache_get(self):
1581+
class Cache:
1582+
def get(self, key, default=None):
1583+
return 1337
1584+
1585+
class ZI(self.klass):
1586+
pass
1587+
# Class attribute must be set after class creation
1588+
# to override zoneinfo.ZoneInfo.__init_subclass__.
1589+
ZI._weak_cache = Cache()
1590+
1591+
with self.assertRaises(RuntimeError) as te:
1592+
ZI("America/Los_Angeles")
1593+
self.assertEqual(
1594+
str(te.exception),
1595+
"Unexpected instance of int in ZI weak cache for key 'America/Los_Angeles'"
1596+
)
1597+
1598+
def test_inconsistent_weak_cache_setdefault(self):
1599+
class Cache:
1600+
def get(self, key, default=None):
1601+
return default
1602+
def setdefault(self, key, value):
1603+
return 1337
1604+
1605+
class ZI(self.klass):
1606+
pass
1607+
# Class attribute must be set after class creation
1608+
# to override zoneinfo.ZoneInfo.__init_subclass__.
1609+
ZI._weak_cache = Cache()
1610+
1611+
with self.assertRaises(RuntimeError) as te:
1612+
ZI("America/Los_Angeles")
1613+
self.assertEqual(
1614+
str(te.exception),
1615+
"Unexpected instance of int in ZI weak cache for key 'America/Los_Angeles'"
1616+
)
1617+
15801618

15811619
class ZoneInfoPickleTest(TzPathUserMixin, ZoneInfoTestBase):
15821620
module = py_zoneinfo
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
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: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,14 +335,23 @@ zoneinfo_ZoneInfo_impl(PyTypeObject *type, PyObject *key)
335335
return NULL;
336336
}
337337

338+
((PyZoneInfo_ZoneInfo *)tmp)->source = SOURCE_CACHE;
338339
instance =
339340
PyObject_CallMethod(weak_cache, "setdefault", "OO", key, tmp);
340341
Py_DECREF(tmp);
341342
if (instance == NULL) {
342343
Py_DECREF(weak_cache);
343344
return NULL;
344345
}
345-
((PyZoneInfo_ZoneInfo *)instance)->source = SOURCE_CACHE;
346+
}
347+
348+
if (!PyObject_TypeCheck(instance, type)) {
349+
PyErr_Format(PyExc_RuntimeError,
350+
"Unexpected instance of %T in %s weak cache for key %R",
351+
instance, _PyType_Name(type), key);
352+
Py_DECREF(instance);
353+
Py_DECREF(weak_cache);
354+
return NULL;
346355
}
347356

348357
update_strong_cache(state, type, key, instance);

0 commit comments

Comments
 (0)