Skip to content

Instantly share code, notes, and snippets.

@oconnor663
Last active October 27, 2022 20:18
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oconnor663/c69cb4dbffb9b13bbced3fe8ce2181ac to your computer and use it in GitHub Desktop.
Save oconnor663/c69cb4dbffb9b13bbced3fe8ce2181ac to your computer and use it in GitHub Desktop.
A demonstration of GIL-releasing hashing leading to a data race in Python
#! /usr/bin/env python3
import hashlib
import threading
def hash_buf(buf):
return hashlib.sha256(buf).hexdigest()
def hash_buf_on_bg_thread(buf):
result = [None]
def work():
result[0] = hash_buf(buf)
thread = threading.Thread(target=work)
thread.start()
return (thread, result)
def main():
buf = bytearray(1_000_000)
# Print the hash of the buffer while it's all zero.
hash_before = hash_buf(buf)
print("hash before:", hash_before)
# Start a background thread to hash the buffer again.
thread, result = hash_buf_on_bg_thread(buf)
# Do two unsynchronized writes, one at the front of the buffer, and one at
# the back. This is at the same time as the background thread is working.
# It will likely miss the first write (either because it's already read the
# front of the buffer, or because our CPU core won't flush its stores
# immediately) but observe the second.
buf[0] = 1
buf[-1] = 1
# Await the background thread and print its result.
thread.join()
hash_during = result[0]
print("hash in bg: ", hash_during)
# Print the hash of the buffer after both writes.
hash_after = hash_buf(buf)
print("hash after: ", hash_after)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment