summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Hupp <adam@hupp.org>2015-10-19 11:07:17 -0700
committerAdam Hupp <adam@hupp.org>2015-10-19 11:08:18 -0700
commit8a35137cdd4b0aa42291e2ce4ad276e47d731cc5 (patch)
tree5887c8c7cc7fe9d7ec4bd55a6b0ae7b7d5103b26
parent569467026d286667803a1a83195dd4d6c3aa5787 (diff)
downloadpython-magic-8a35137cdd4b0aa42291e2ce4ad276e47d731cc5.tar.gz
Replace per-thread Magic instance with a lock. Tested with a stress
stest that runs a 100 from_file checks on a 100 threads, concurrently. This almost immediately causes a SEVG without the lock, and runs successfully with the lock.
-rw-r--r--magic.py39
1 files changed, 15 insertions, 24 deletions
diff --git a/magic.py b/magic.py
index 9e5c6de..87550b6 100644
--- a/magic.py
+++ b/magic.py
@@ -57,33 +57,32 @@ class Magic:
self.flags |= MAGIC_COMPRESS
self.cookie = magic_open(self.flags)
-
+ self.lock = threading.Lock()
+
magic_load(self.cookie, magic_file)
- self.thread = threading.currentThread()
-
def from_buffer(self, buf):
"""
Identify the contents of `buf`
"""
- self._thread_check()
- try:
- return magic_buffer(self.cookie, buf)
- except MagicException as e:
- return self._handle509Bug(e)
+ with self.lock:
+ try:
+ return magic_buffer(self.cookie, buf)
+ except MagicException as e:
+ return self._handle509Bug(e)
def from_file(self, filename):
"""
Identify the contents of file `filename`
raises IOError if the file does not exist
"""
- self._thread_check()
if not os.path.exists(filename):
raise IOError("File does not exist: " + filename)
- try:
- return magic_file(self.cookie, filename)
- except MagicException as e:
- return self._handle509Bug(e)
+ with self.lock:
+ try:
+ return magic_file(self.cookie, filename)
+ except MagicException as e:
+ return self._handle509Bug(e)
def _handle509Bug(self, e):
# libmagic 5.09 has a bug where it might fail to identify the
@@ -92,13 +91,6 @@ class Magic:
if e.message is None and (self.flags & MAGIC_MIME):
return "application/octet-stream"
- def _thread_check(self):
- if self.thread != threading.currentThread():
- raise Exception('attempting to use libmagic on multiple threads will '
- 'end in SEGV. Prefer to use the module functions '
- 'from_file or from_buffer, or carefully manage direct '
- 'use of the Magic class')
-
def __del__(self):
# no _thread_check here because there can be no other
# references to this object at this point.
@@ -114,13 +106,12 @@ class Magic:
magic_close(self.cookie)
self.cookie = None
-
-instances = threading.local()
+_instances = {}
def _get_magic_type(mime):
- i = instances.__dict__.get(mime)
+ i = _instances.get(mime)
if i is None:
- i = instances.__dict__[mime] = Magic(mime=mime)
+ i = _instances[mime] = Magic(mime=mime)
return i
def from_file(filename, mime=False):