◐ Shell
clean mode source ↗

Race condition writing objects in LooseObjectDB

There's a TOCTTOU in LooseObjectDB when storing a new object, that causes storing an object to fail with FileExistsError:

   File "patch_tree.py", line 132, in write_tree
     return self.db.store(istream).binsha
   File ".venv/lib/python3.9/gitdb/db/git.py", line 77, in store
     return self._loose_db.store(istream)
   File ".venv/lib/python3.9/gitdb/db/loose.py", line 226, in store
     mkdir(obj_dir)
FileExistsError: [Errno 17] File exists: '/tmp/tmp.flUcclypOQ/objects/a0'

The problem code is

            if not isdir(obj_dir):
                mkdir(obj_dir)

and what is happening is

  1. isdir() returns False because the directory does not exist at that moment
  2. The directory is created in another thread
  3. mkdir() fails with FileExistsError

This can be avoided by using an EAFP pattern, e.g.

with contextlib.suppress(FileExistsError):
    mkdir(obj_dir)