From f18007947a46429b5308dbfbcac7642f7f5a26e8 Mon Sep 17 00:00:00 2001 From: Duane Griffin Date: Mon, 12 Sep 2016 14:34:16 +1200 Subject: [PATCH] Issue #27945: fix dictitems_contains use-after-free Take a reference on the dictionary value before comparing it as otherwise the comparison can mutate the dictionary and invalidate it. --- Lib/test/test_dict.py | 9 +++++++++ Objects/dictobject.c | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py index fb954c8..ebdb629 100644 --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -1029,6 +1029,15 @@ class DictTest(unittest.TestCase): support.check_free_after_iterating(self, lambda d: iter(d.values()), dict) support.check_free_after_iterating(self, lambda d: iter(d.items()), dict) + def test_dictitems_contains_use_after_free(self): + class X: + def __eq__(self, other): + d.clear() + return NotImplemented + + d = {0: set()} + (0, X()) in d.items() + from test import mapping_tests class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol): diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 4bcc3db..56b06db 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -3942,6 +3942,7 @@ dictitems_iter(_PyDictViewObject *dv) static int dictitems_contains(_PyDictViewObject *dv, PyObject *obj) { + int result; PyObject *key, *value, *found; if (dv->dv_dict == NULL) return 0; @@ -3955,7 +3956,10 @@ dictitems_contains(_PyDictViewObject *dv, PyObject *obj) return -1; return 0; } - return PyObject_RichCompareBool(value, found, Py_EQ); + Py_INCREF(found); + result = PyObject_RichCompareBool(value, found, Py_EQ); + Py_DECREF(found); + return result; } static PySequenceMethods dictitems_as_sequence = { -- 2.10.0