mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2026-10-29 04:17:24 +08:00
Fix for Ctrl-C hang on Python 3.14 (leaked cache locks)
This commit is contained in:
+37
-2
@@ -9,8 +9,40 @@ import copy
|
||||
import threading
|
||||
|
||||
from collections import OrderedDict
|
||||
from thirdparty import six
|
||||
from thirdparty.six.moves import collections_abc as _collections
|
||||
|
||||
class NoLock(object):
|
||||
"""
|
||||
No-op stand-in for a lock, used where the guarded operations are already atomic on their own
|
||||
|
||||
>>> with NoLock():
|
||||
... True
|
||||
True
|
||||
"""
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, *args):
|
||||
return False
|
||||
|
||||
def cacheLock(reentrant=False):
|
||||
"""
|
||||
Returns a lock for guarding the (OrderedDict based) caches. Only Python 2 needs a real one, as its
|
||||
OrderedDict is implemented in Python (#5619), while on Python 3 each operation is atomic. Moreover,
|
||||
since Python 3.14 a Ctrl-C landing right after a lock got acquired by the 'with' statement leaves it
|
||||
acquired forever (i.e. '__exit__' never gets called), hanging every thread that touches the cache
|
||||
|
||||
>>> isinstance(cacheLock(), NoLock) == six.PY3
|
||||
True
|
||||
"""
|
||||
|
||||
if six.PY2:
|
||||
return threading.RLock() if reentrant else threading.Lock()
|
||||
else:
|
||||
return NoLock()
|
||||
|
||||
class AttribDict(dict):
|
||||
"""
|
||||
This class defines the dictionary with added capability to access members as attributes
|
||||
@@ -133,7 +165,7 @@ class LRUDict(object):
|
||||
def __init__(self, capacity):
|
||||
self.capacity = capacity
|
||||
self.cache = OrderedDict()
|
||||
self.__lock = threading.Lock()
|
||||
self.__lock = cacheLock()
|
||||
|
||||
def __len__(self):
|
||||
return len(self.cache)
|
||||
@@ -159,7 +191,10 @@ class LRUDict(object):
|
||||
self.cache.pop(key)
|
||||
except KeyError:
|
||||
if len(self.cache) >= self.capacity:
|
||||
self.cache.popitem(last=False)
|
||||
try:
|
||||
self.cache.popitem(last=False)
|
||||
except KeyError: # Note: concurrently emptied by another thread (unlocked on Python 3)
|
||||
pass
|
||||
self.cache[key] = value
|
||||
|
||||
def set(self, key, value):
|
||||
|
||||
@@ -9,6 +9,7 @@ import functools
|
||||
import threading
|
||||
|
||||
from lib.core.datatype import LRUDict
|
||||
from lib.core.datatype import cacheLock
|
||||
from lib.core.settings import MAX_CACHE_ITEMS
|
||||
from lib.core.threads import getCurrentThreadData
|
||||
|
||||
@@ -40,7 +41,7 @@ def cachedmethod(f):
|
||||
"""
|
||||
|
||||
_cache[f] = LRUDict(capacity=MAX_CACHE_ITEMS)
|
||||
_method_locks[f] = threading.RLock()
|
||||
_method_locks[f] = cacheLock(reentrant=True)
|
||||
|
||||
def _freeze(val):
|
||||
if isinstance(val, (list, set, tuple)):
|
||||
@@ -60,8 +61,10 @@ def cachedmethod(f):
|
||||
key = args
|
||||
|
||||
with lock:
|
||||
if key in cache:
|
||||
try:
|
||||
return cache[key]
|
||||
except KeyError: # Note: single lookup, as an entry can get evicted in between (unlocked on Python 3)
|
||||
pass
|
||||
|
||||
except TypeError:
|
||||
# Note: fallback (slow-path) for unhashable arguments
|
||||
@@ -72,8 +75,10 @@ def cachedmethod(f):
|
||||
key = (_FROZEN_KEY_MARKER, _freeze(args))
|
||||
|
||||
with lock:
|
||||
if key in cache:
|
||||
try:
|
||||
return cache[key]
|
||||
except KeyError:
|
||||
pass
|
||||
except TypeError:
|
||||
# Note: genuinely uncacheable arguments; skip caching altogether
|
||||
return f(*args, **kwargs)
|
||||
|
||||
@@ -19,7 +19,7 @@ from lib.core.enums import OS
|
||||
from thirdparty import six
|
||||
|
||||
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
||||
VERSION = "1.10.10.24"
|
||||
VERSION = "1.10.10.25"
|
||||
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
|
||||
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
|
||||
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)
|
||||
|
||||
Reference in New Issue
Block a user