compiler: do not pass files to external tools while they are opened.

This fixes access violations on Windows that are present both with
input and output files. For some reason, Cygwin-compiled binutils
did not exhibit this problem, but MSYS-compiled binutils do.

Fixes #961.
This commit is contained in:
whitequark 2018-03-15 22:21:29 +00:00
parent 5cb2602021
commit 4b5a78e231
1 changed files with 29 additions and 26 deletions

View File

@ -1,4 +1,4 @@
import os, sys, tempfile, subprocess import os, sys, tempfile, subprocess, io
from artiq.compiler import types from artiq.compiler import types
from llvmlite_artiq import ir as ll, binding as llvm from llvmlite_artiq import ir as ll, binding as llvm
@ -8,27 +8,25 @@ llvm.initialize_all_asmprinters()
class RunTool: class RunTool:
def __init__(self, pattern, **tempdata): def __init__(self, pattern, **tempdata):
self.files = [] self._pattern = pattern
self.pattern = pattern self._tempdata = tempdata
self.tempdata = tempdata self._tempnames = {}
self._tempfiles = {}
def maketemp(self, data):
f = tempfile.NamedTemporaryFile()
f.write(data)
f.flush()
self.files.append(f)
return f
def __enter__(self): def __enter__(self):
tempfiles = {} for key, data in self._tempdata.items():
tempnames = {} if data is None:
for key in self.tempdata: fd, filename = tempfile.mkstemp()
tempfiles[key] = self.maketemp(self.tempdata[key]) os.close(fd)
tempnames[key] = tempfiles[key].name self._tempnames[key] = filename
else:
with tempfile.NamedTemporaryFile(delete=False) as f:
f.write(data)
self._tempnames[key] = f.name
cmdline = [] cmdline = []
for argument in self.pattern: for argument in self._pattern:
cmdline.append(argument.format(**tempnames)) cmdline.append(argument.format(**self._tempnames))
process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE) process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = process.communicate() stdout, stderr = process.communicate()
@ -36,12 +34,17 @@ class RunTool:
raise Exception("{} invocation failed: {}". raise Exception("{} invocation failed: {}".
format(cmdline[0], stderr.decode('utf-8'))) format(cmdline[0], stderr.decode('utf-8')))
tempfiles["__stdout__"] = stdout.decode('utf-8') self._tempfiles["__stdout__"] = io.StringIO(stdout.decode('utf-8'))
return tempfiles for key in self._tempdata:
if self._tempdata[key] is None:
self._tempfiles[key] = open(self._tempnames[key], "rb")
return self._tempfiles
def __exit__(self, exc_typ, exc_value, exc_trace): def __exit__(self, exc_typ, exc_value, exc_trace):
for f in self.files: for file in self._tempfiles.values():
f.close() file.close()
for filename in self._tempnames.values():
os.unlink(filename)
def _dump(target, kind, suffix, content): def _dump(target, kind, suffix, content):
if target is not None: if target is not None:
@ -166,7 +169,7 @@ class Target:
with RunTool([self.triple + "-ld", "-shared", "--eh-frame-hdr"] + with RunTool([self.triple + "-ld", "-shared", "--eh-frame-hdr"] +
["{{obj{}}}".format(index) for index in range(len(objects))] + ["{{obj{}}}".format(index) for index in range(len(objects))] +
["-o", "{output}"], ["-o", "{output}"],
output=b"", output=None,
**{"obj{}".format(index): obj for index, obj in enumerate(objects)}) \ **{"obj{}".format(index): obj for index, obj in enumerate(objects)}) \
as results: as results:
library = results["output"].read() library = results["output"].read()
@ -181,7 +184,7 @@ class Target:
def strip(self, library): def strip(self, library):
with RunTool([self.triple + "-strip", "--strip-debug", "{library}", "-o", "{output}"], with RunTool([self.triple + "-strip", "--strip-debug", "{library}", "-o", "{output}"],
library=library, output=b"") \ library=library, output=None) \
as results: as results:
return results["output"].read() return results["output"].read()
@ -198,7 +201,7 @@ class Target:
"--demangle", "--exe={library}"] + offset_addresses, "--demangle", "--exe={library}"] + offset_addresses,
library=library) \ library=library) \
as results: as results:
lines = iter(results["__stdout__"].rstrip().split("\n")) lines = iter(results["__stdout__"].read().rstrip().split("\n"))
backtrace = [] backtrace = []
while True: while True:
try: try:
@ -226,7 +229,7 @@ class Target:
def demangle(self, names): def demangle(self, names):
with RunTool([self.triple + "-c++filt"] + names) as results: with RunTool([self.triple + "-c++filt"] + names) as results:
return results["__stdout__"].rstrip().split("\n") return results["__stdout__"].read().rstrip().split("\n")
class NativeTarget(Target): class NativeTarget(Target):
def __init__(self): def __init__(self):