checksum.py: detect PyPy crashes in hashlib
authorZac Medico <zmedico@gentoo.org>
Thu, 1 Dec 2011 23:25:31 +0000 (15:25 -0800)
committerZac Medico <zmedico@gentoo.org>
Thu, 1 Dec 2011 23:25:31 +0000 (15:25 -0800)
Use a fork to try and PyPy by digesting random data with hashlib
functions. It doesn't look like a bug has been reported upstream for
this yet, so it may or may not be reproducible by others. Anyway, this
allows me to avoid crashing the main PyPy process until I find a real
fix.

pym/portage/checksum.py

index f10fc4d55a05e99c33370e73ef373b6179257b48..77035b600f6338524a3055218c14115e48cb38f6 100644 (file)
@@ -9,6 +9,7 @@ from portage import os
 from portage import _encodings
 from portage import _unicode_encode
 import errno
+import platform
 import stat
 import tempfile
 
@@ -61,6 +62,28 @@ class _generate_hash_function(object):
 
                return (checksum.hexdigest(), size)
 
+_test_hash_func = False
+if platform.python_implementation() == 'PyPy':
+       def _test_hash_func(constructor):
+               """
+               Test for PyPy crashes observed with hashlib's ripemd160 and whirlpool
+               functions executed under pypy-1.7 with Python 2.7.1:
+               *** glibc detected *** pypy-c1.7: free(): invalid next size (fast): 0x0b963a38 ***
+               *** glibc detected *** pypy-c1.7: free(): corrupted unsorted chunks: 0x09c490b0 ***
+               """
+               import random
+               pid = os.fork()
+               if pid == 0:
+                       data = list(b'abcdefg')
+                       for i in range(10):
+                               checksum = constructor()
+                               random.shuffle(data)
+                               checksum.update(b''.join(data))
+                               checksum.hexdigest()
+                       os._exit(os.EX_OK)
+               pid, status = os.waitpid(pid, 0)
+               return os.WIFEXITED(status) and os.WEXITSTATUS(status) == os.EX_OK
+
 # Define hash functions, try to use the best module available. Later definitions
 # override earlier ones
 
@@ -129,6 +152,12 @@ try:
                except ValueError:
                        pass
                else:
+                       if _test_hash_func and \
+                               not _test_hash_func(functools.partial(hashlib.new, hash_name)):
+                               portage.util.writemsg("\n!!! hash function appears to "
+                                       "crash python: %s from %s\n" %
+                                       (hash_name, "hashlib"), noiselevel=-1)
+                               continue
                        globals()['%shash' % local_name] = \
                                _generate_hash_function(local_name.upper(), \
                                functools.partial(hashlib.new, hash_name), \