summaryrefslogtreecommitdiffstats
path: root/Lib/test
diff options
context:
space:
mode:
authorRaymond Hettinger <rhettinger@users.noreply.github.com>2019-01-26 08:02:00 (GMT)
committerGitHub <noreply@github.com>2019-01-26 08:02:00 (GMT)
commitd8080c01195cc9a19af752bfa04d98824dd9fb15 (patch)
tree75ab01426d6a329ad2987f58b5261443a0ee7c0e /Lib/test
parentadad9e68013aac166c84ffe4e23f3a5464f41840 (diff)
downloadcpython-d8080c01195cc9a19af752bfa04d98824dd9fb15.zip
cpython-d8080c01195cc9a19af752bfa04d98824dd9fb15.tar.gz
cpython-d8080c01195cc9a19af752bfa04d98824dd9fb15.tar.bz2
bpo-35780: Fix errors in lru_cache() C code (GH-11623)
Diffstat (limited to 'Lib/test')
-rw-r--r--Lib/test/test_functools.py29
1 files changed, 28 insertions, 1 deletions
diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py
index ffbd0fc..63a9ade 100644
--- a/Lib/test/test_functools.py
+++ b/Lib/test/test_functools.py
@@ -1233,6 +1233,33 @@ class TestLRU:
self.assertEqual(misses, 4)
self.assertEqual(currsize, 2)
+ def test_lru_bug_35780(self):
+ # C version of the lru_cache was not checking to see if
+ # the user function call has already modified the cache
+ # (this arises in recursive calls and in multi-threading).
+ # This cause the cache to have orphan links not referenced
+ # by the cache dictionary.
+
+ once = True # Modified by f(x) below
+
+ @self.module.lru_cache(maxsize=10)
+ def f(x):
+ nonlocal once
+ rv = f'.{x}.'
+ if x == 20 and once:
+ once = False
+ rv = f(x)
+ return rv
+
+ # Fill the cache
+ for x in range(15):
+ self.assertEqual(f(x), f'.{x}.')
+ self.assertEqual(f.cache_info().currsize, 10)
+
+ # Make a recursive call and make sure the cache remains full
+ self.assertEqual(f(20), '.20.')
+ self.assertEqual(f.cache_info().currsize, 10)
+
def test_lru_hash_only_once(self):
# To protect against weird reentrancy bugs and to improve
# efficiency when faced with slow __hash__ methods, the
@@ -1329,7 +1356,7 @@ class TestLRU:
for i in (0, 1):
self.assertEqual([eq(n) for n in range(150)], list(range(150)))
self.assertEqual(eq.cache_info(),
- self.module._CacheInfo(hits=0, misses=300, maxsize=-10, currsize=1))
+ self.module._CacheInfo(hits=0, misses=300, maxsize=0, currsize=0))
def test_lru_with_exceptions(self):
# Verify that user_function exceptions get passed through without