From baa6b4e3e4f9e69b3c63706b996c02661ffe6aff Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Tue, 30 Apr 2013 11:23:11 -0400 Subject: [PATCH] The cache key for safe_exec has to be hashed to keep it a reasonable size. --- common/lib/capa/capa/safe_exec/safe_exec.py | 7 ++++++- .../capa/capa/safe_exec/tests/test_safe_exec.py | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/common/lib/capa/capa/safe_exec/safe_exec.py b/common/lib/capa/capa/safe_exec/safe_exec.py index a07fe359fd..3fd6c215b7 100644 --- a/common/lib/capa/capa/safe_exec/safe_exec.py +++ b/common/lib/capa/capa/safe_exec/safe_exec.py @@ -4,6 +4,8 @@ from codejail.safe_exec import safe_exec as codejail_safe_exec from codejail.safe_exec import json_safe from . import lazymod +import hashlib + # Establish the Python environment for Capa. # Capa assumes float-friendly division always. # The name "random" is a properly-seeded stand-in for the random module. @@ -53,7 +55,10 @@ def safe_exec(code, globals_dict, random_seed=None, python_path=None, cache=None # Check the cache for a previous result. if cache: canonical_globals = sorted(json_safe(globals_dict).iteritems()) - key = "safe_exec %r %s %r" % (random_seed, code, canonical_globals) + md5er = hashlib.md5() + md5er.update(code) + md5er.update(repr(canonical_globals)) + key = "safe_exec %r %s" % (random_seed, md5er.hexdigest()) cached = cache.get(key) if cached is not None: globals_dict.update(cached) diff --git a/common/lib/capa/capa/safe_exec/tests/test_safe_exec.py b/common/lib/capa/capa/safe_exec/tests/test_safe_exec.py index 37f86383c2..bd960f331c 100644 --- a/common/lib/capa/capa/safe_exec/tests/test_safe_exec.py +++ b/common/lib/capa/capa/safe_exec/tests/test_safe_exec.py @@ -65,9 +65,13 @@ class DictCache(object): self.cache = d def get(self, key): + # Actual cache implementations have limits on key length + assert len(key) <= 250 return self.cache.get(key) def set(self, key, value): + # Actual cache implementations have limits on key length + assert len(key) <= 250 self.cache[key] = value @@ -90,3 +94,13 @@ class TestSafeExecCaching(unittest.TestCase): g = {} safe_exec("a = int(math.pi)", g, cache=DictCache(cache)) self.assertEqual(g['a'], 17) + + def test_cache_large_code_chunk(self): + # Caching used to die on memcache with more than 250 bytes of code. + # Check that it doesn't any more. + code = "a = 0\n" + ("a += 1\n" * 12345) + + g = {} + cache = {} + safe_exec(code, g, cache=DictCache(cache)) + self.assertEqual(g['a'], 12345)