]> granicus.if.org Git - python/commitdiff
Issue #28653: Fix a refleak in functools.lru_cache.
authorYury Selivanov <yury@magic.io>
Wed, 9 Nov 2016 23:55:45 +0000 (18:55 -0500)
committerYury Selivanov <yury@magic.io>
Wed, 9 Nov 2016 23:55:45 +0000 (18:55 -0500)
Lib/test/test_functools.py
Misc/NEWS
Modules/_functoolsmodule.c

index 50766449524ef3c50ca53bde2b52b9b0d2098e5c..6a3bf649633f8a7ef3fb3c519ab9c70695ad2d4d 100644 (file)
@@ -1162,6 +1162,25 @@ class TestLRU:
         self.assertEqual(misses, 4)
         self.assertEqual(currsize, 2)
 
+    def test_lru_type_error(self):
+        # Regression test for issue #28653.
+        # lru_cache was leaking when one of the arguments
+        # wasn't cacheable.
+
+        @functools.lru_cache(maxsize=None)
+        def infinite_cache(o):
+            pass
+
+        @functools.lru_cache(maxsize=10)
+        def limited_cache(o):
+            pass
+
+        with self.assertRaises(TypeError):
+            infinite_cache([])
+
+        with self.assertRaises(TypeError):
+            limited_cache([])
+
     def test_lru_with_maxsize_none(self):
         @self.module.lru_cache(maxsize=None)
         def fib(n):
index f9e2f7225b711bd4535db310821b0b4271213b68..c50ce124196f17a11aa9cc40acd4e0be443a3993 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -457,6 +457,8 @@ Library
 
 - Issue #28652: Make loop methods reject socket kinds they do not support.
 
+- Issue #28653: Fix a refleak in functools.lru_cache.
+
 IDLE
 ----
 
index d785c4932b6f4bb747d637c0881f48be44b6ccce..9c9ab5f8ea2f1c99776d4199b3ec365f55b0396a 100644 (file)
@@ -781,8 +781,10 @@ infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwd
     if (!key)
         return NULL;
     hash = PyObject_Hash(key);
-    if (hash == -1)
+    if (hash == -1) {
+        Py_DECREF(key);
         return NULL;
+    }
     result = _PyDict_GetItem_KnownHash(self->cache, key, hash);
     if (result) {
         Py_INCREF(result);
@@ -837,8 +839,10 @@ bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds
     if (!key)
         return NULL;
     hash = PyObject_Hash(key);
-    if (hash == -1)
+    if (hash == -1) {
+        Py_DECREF(key);
         return NULL;
+    }
     link  = (lru_list_elem *)_PyDict_GetItem_KnownHash(self->cache, key, hash);
     if (link) {
         lru_cache_extricate_link(link);