diff options
| author | Adam Hupp <adam@hupp.org> | 2015-10-19 11:07:17 -0700 |
|---|---|---|
| committer | Adam Hupp <adam@hupp.org> | 2015-10-19 11:08:18 -0700 |
| commit | 8a35137cdd4b0aa42291e2ce4ad276e47d731cc5 (patch) | |
| tree | 5887c8c7cc7fe9d7ec4bd55a6b0ae7b7d5103b26 | |
| parent | 569467026d286667803a1a83195dd4d6c3aa5787 (diff) | |
| download | python-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.py | 39 |
1 files changed, 15 insertions, 24 deletions
@@ -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): |
