Skip to content

Commit 6af8ef0

Browse files
committed
Fix a race condition in TexManager.make_dvi.
Previously, a race condition could occur if, while a process had called make_tex (generating the tex file in the global cache) and was going to call the latex subprocess (to generate the dvi file), another process also called make_tex for the same tex string and started rewriting the tex source. In that case, the latex subprocess could see a partially written (invalid) tex source. Fix that by generating the tex source in a process-private temporary directory, where the latex process is already going to run anyways. (This is cheap compared to the latex subprocess invocation.)
1 parent 780e66c commit 6af8ef0

File tree

1 file changed

+8
-6
lines changed

1 file changed

+8
-6
lines changed

lib/matplotlib/texmanager.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,10 @@ def make_dvi(cls, tex, fontsize):
284284
basefile = cls.get_basefile(tex, fontsize)
285285
dvifile = '%s.dvi' % basefile
286286
if not os.path.exists(dvifile):
287-
texfile = Path(cls.make_tex(tex, fontsize))
288-
# Generate the dvi in a temporary directory to avoid race
287+
# Also generate the tex source in the main cache directory, but
288+
# only for backcompat.
289+
cls.make_tex(tex, fontsize)
290+
# Generate the tex and dvi in a temporary directory to avoid race
289291
# conditions e.g. if multiple processes try to process the same tex
290292
# string at the same time. Having tmpdir be a subdirectory of the
291293
# final output dir ensures that they are on the same filesystem,
@@ -296,12 +298,12 @@ def make_dvi(cls, tex, fontsize):
296298
# will be blocked when `openin_any = p` in texmf.cnf).
297299
cwd = Path(dvifile).parent
298300
with TemporaryDirectory(dir=cwd) as tmpdir:
299-
tmppath = Path(tmpdir)
301+
Path(tmpdir, "file.tex").write_text(
302+
cls._get_tex_source(tex, fontsize), encoding='utf-8')
300303
cls._run_checked_subprocess(
301304
["latex", "-interaction=nonstopmode", "--halt-on-error",
302-
f"--output-directory={tmppath.name}",
303-
f"{texfile.name}"], tex, cwd=cwd)
304-
(tmppath / Path(dvifile).name).replace(dvifile)
305+
"file.tex"], tex, cwd=tmpdir)
306+
Path(tmpdir, "file.dvi").replace(dvifile)
305307
return dvifile
306308

307309
@classmethod

0 commit comments

Comments
 (0)