(self)
| 1696 | @threading_helper.reap_threads |
| 1697 | @threading_helper.requires_working_threading() |
| 1698 | def test_unpickle_module_race(self): |
| 1699 | # https://bugs.python.org/issue34572 |
| 1700 | locker_module = dedent(""" |
| 1701 | import threading |
| 1702 | barrier = threading.Barrier(2) |
| 1703 | """) |
| 1704 | locking_import_module = dedent(""" |
| 1705 | import locker |
| 1706 | locker.barrier.wait() |
| 1707 | class ToBeUnpickled(object): |
| 1708 | pass |
| 1709 | """) |
| 1710 | |
| 1711 | os.mkdir(TESTFN) |
| 1712 | self.addCleanup(shutil.rmtree, TESTFN) |
| 1713 | sys.path.insert(0, TESTFN) |
| 1714 | self.addCleanup(sys.path.remove, TESTFN) |
| 1715 | with open(os.path.join(TESTFN, "locker.py"), "wb") as f: |
| 1716 | f.write(locker_module.encode('utf-8')) |
| 1717 | with open(os.path.join(TESTFN, "locking_import.py"), "wb") as f: |
| 1718 | f.write(locking_import_module.encode('utf-8')) |
| 1719 | self.addCleanup(forget, "locker") |
| 1720 | self.addCleanup(forget, "locking_import") |
| 1721 | |
| 1722 | import locker |
| 1723 | |
| 1724 | pickle_bytes = ( |
| 1725 | b'\x80\x03clocking_import\nToBeUnpickled\nq\x00)\x81q\x01.') |
| 1726 | |
| 1727 | # Then try to unpickle two of these simultaneously |
| 1728 | # One of them will cause the module import, and we want it to block |
| 1729 | # until the other one either: |
| 1730 | # - fails (before the patch for this issue) |
| 1731 | # - blocks on the import lock for the module, as it should |
| 1732 | results = [] |
| 1733 | barrier = threading.Barrier(3) |
| 1734 | def t(): |
| 1735 | # This ensures the threads have all started |
| 1736 | # presumably barrier release is faster than thread startup |
| 1737 | barrier.wait() |
| 1738 | results.append(pickle.loads(pickle_bytes)) |
| 1739 | |
| 1740 | t1 = threading.Thread(target=t) |
| 1741 | t2 = threading.Thread(target=t) |
| 1742 | t1.start() |
| 1743 | t2.start() |
| 1744 | |
| 1745 | barrier.wait() |
| 1746 | # could have delay here |
| 1747 | locker.barrier.wait() |
| 1748 | |
| 1749 | t1.join() |
| 1750 | t2.join() |
| 1751 | |
| 1752 | from locking_import import ToBeUnpickled |
| 1753 | self.assertEqual( |
| 1754 | [type(x) for x in results], |
| 1755 | [ToBeUnpickled] * 2) |
nothing calls this directly
no test coverage detected