https://github.com/python/cpython/commit/8307a14d0edc14ae2f775995720e4b6d6dc865b3
commit: 8307a14d0edc14ae2f775995720e4b6d6dc865b3
branch: main
author: wangxiaolei <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2025-12-17T08:35:08Z
summary:
gh-142783: Fix possible use after free in zoneinfo module (GH-142790)
files:
A Misc/NEWS.d/next/Library/2025-12-16-14-49-19.gh-issue-142783.VPV1ig.rst
M Lib/test/test_zoneinfo/test_zoneinfo.py
M Modules/_zoneinfo.c
diff --git a/Lib/test/test_zoneinfo/test_zoneinfo.py
b/Lib/test/test_zoneinfo/test_zoneinfo.py
index fad741e477b84a..8f3ca59c9ef5ed 100644
--- a/Lib/test/test_zoneinfo/test_zoneinfo.py
+++ b/Lib/test/test_zoneinfo/test_zoneinfo.py
@@ -1551,6 +1551,26 @@ def __eq__(self, other):
except CustomError:
pass
+ def test_weak_cache_descriptor_use_after_free(self):
+ class BombDescriptor:
+ def __get__(self, obj, owner):
+ return {}
+
+ class EvilZoneInfo(self.klass):
+ pass
+
+ # Must be set after the class creation.
+ EvilZoneInfo._weak_cache = BombDescriptor()
+
+ key = "America/Los_Angeles"
+ zone1 = EvilZoneInfo(key)
+ self.assertEqual(str(zone1), key)
+
+ EvilZoneInfo.clear_cache()
+ zone2 = EvilZoneInfo(key)
+ self.assertEqual(str(zone2), key)
+ self.assertIsNot(zone2, zone1)
+
class CZoneInfoCacheTest(ZoneInfoCacheTest):
module = c_zoneinfo
diff --git
a/Misc/NEWS.d/next/Library/2025-12-16-14-49-19.gh-issue-142783.VPV1ig.rst
b/Misc/NEWS.d/next/Library/2025-12-16-14-49-19.gh-issue-142783.VPV1ig.rst
new file mode 100644
index 00000000000000..f014771ae9a146
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-12-16-14-49-19.gh-issue-142783.VPV1ig.rst
@@ -0,0 +1 @@
+Fix zoneinfo use-after-free with descriptor _weak_cache. a descriptor as
_weak_cache could cause crashes during object creation. The fix ensures proper
reference counting for descriptor-provided objects.
diff --git a/Modules/_zoneinfo.c b/Modules/_zoneinfo.c
index b99be073db5460..e07dfd19efa06d 100644
--- a/Modules/_zoneinfo.c
+++ b/Modules/_zoneinfo.c
@@ -292,16 +292,11 @@ static PyObject *
get_weak_cache(zoneinfo_state *state, PyTypeObject *type)
{
if (type == state->ZoneInfoType) {
+ Py_INCREF(state->ZONEINFO_WEAK_CACHE);
return state->ZONEINFO_WEAK_CACHE;
}
else {
- PyObject *cache =
- PyObject_GetAttrString((PyObject *)type, "_weak_cache");
- // We are assuming that the type lives at least as long as the function
- // that calls get_weak_cache, and that it holds a reference to the
- // cache, so we'll return a "borrowed reference".
- Py_XDECREF(cache);
- return cache;
+ return PyObject_GetAttrString((PyObject *)type, "_weak_cache");
}
}
@@ -328,6 +323,7 @@ zoneinfo_ZoneInfo_impl(PyTypeObject *type, PyObject *key)
PyObject *weak_cache = get_weak_cache(state, type);
instance = PyObject_CallMethod(weak_cache, "get", "O", key, Py_None);
if (instance == NULL) {
+ Py_DECREF(weak_cache);
return NULL;
}
@@ -335,6 +331,7 @@ zoneinfo_ZoneInfo_impl(PyTypeObject *type, PyObject *key)
Py_DECREF(instance);
PyObject *tmp = zoneinfo_new_instance(state, type, key);
if (tmp == NULL) {
+ Py_DECREF(weak_cache);
return NULL;
}
@@ -342,12 +339,14 @@ zoneinfo_ZoneInfo_impl(PyTypeObject *type, PyObject *key)
PyObject_CallMethod(weak_cache, "setdefault", "OO", key, tmp);
Py_DECREF(tmp);
if (instance == NULL) {
+ Py_DECREF(weak_cache);
return NULL;
}
((PyZoneInfo_ZoneInfo *)instance)->source = SOURCE_CACHE;
}
update_strong_cache(state, type, key, instance);
+ Py_DECREF(weak_cache);
return instance;
}
@@ -510,12 +509,14 @@ zoneinfo_ZoneInfo_clear_cache_impl(PyTypeObject *type,
PyTypeObject *cls,
PyObject *item = NULL;
PyObject *pop = PyUnicode_FromString("pop");
if (pop == NULL) {
+ Py_DECREF(weak_cache);
return NULL;
}
PyObject *iter = PyObject_GetIter(only_keys);
if (iter == NULL) {
Py_DECREF(pop);
+ Py_DECREF(weak_cache);
return NULL;
}
@@ -540,6 +541,7 @@ zoneinfo_ZoneInfo_clear_cache_impl(PyTypeObject *type,
PyTypeObject *cls,
Py_DECREF(pop);
}
+ Py_DECREF(weak_cache);
if (PyErr_Occurred()) {
return NULL;
}
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]