Skip to content

Commit 5174e09

Browse files
committed
[lldb] Don't use NamedTemporaryFile to test compiler support
You cannot use a NamedTempFile with an external process because it may not be flushed to disk. The safest and most portable approach is to close the file, call the other process and then unlink the file manually. Presumably this works fine on Linux, but it fails on Darwin when targeting remote-linux. See https://bugs.python.org/issue29573
1 parent f623702 commit 5174e09

File tree

3 files changed

+99
-76
lines changed

3 files changed

+99
-76
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
"""
2+
Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3+
See https://llvm.org/LICENSE.txt for license information.
4+
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5+
"""
6+
7+
import os
8+
import tempfile
9+
10+
11+
class OnDiskTempFile:
12+
def __init__(self, delete=True):
13+
self.path = None
14+
15+
def __enter__(self):
16+
fd, path = tempfile.mkstemp()
17+
os.close(fd)
18+
self.path = path
19+
return self
20+
21+
def __exit__(self, exc_type, exc_val, exc_tb):
22+
if os.path.exists(self.path):
23+
os.remove(self.path)

lldb/packages/Python/lldbsuite/test/decorators.py

Lines changed: 71 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from . import test_categories
2121
from . import lldbtest_config
2222
from lldbsuite.support import funcutils
23+
from lldbsuite.support import temp_file
2324
from lldbsuite.test import lldbplatform
2425
from lldbsuite.test import lldbplatformutil
2526

@@ -94,22 +95,23 @@ def _match_decorator_property(expected, actual):
9495

9596

9697
def _compiler_supports(
97-
compiler, flag, source="int main() {}", output_file=tempfile.NamedTemporaryFile()
98+
compiler, flag, source="int main() {}", output_file=temp_file.OnDiskTempFile()
9899
):
99100
"""Test whether the compiler supports the given flag."""
100-
if platform.system() == "Darwin":
101-
compiler = "xcrun " + compiler
102-
try:
103-
cmd = "echo '%s' | %s %s -x c -o %s -" % (
104-
source,
105-
compiler,
106-
flag,
107-
output_file.name,
108-
)
109-
subprocess.check_call(cmd, shell=True)
110-
except subprocess.CalledProcessError:
111-
return False
112-
return True
101+
with output_file:
102+
if platform.system() == "Darwin":
103+
compiler = "xcrun " + compiler
104+
try:
105+
cmd = "echo '%s' | %s %s -x c -o %s -" % (
106+
source,
107+
compiler,
108+
flag,
109+
output_file.path,
110+
)
111+
subprocess.check_call(cmd, shell=True)
112+
except subprocess.CalledProcessError:
113+
return False
114+
return True
113115

114116

115117
def expectedFailureIf(condition, bugnumber=None):
@@ -876,19 +878,19 @@ def skipUnlessSupportedTypeAttribute(attr):
876878

877879
def compiler_doesnt_support_struct_attribute():
878880
compiler_path = lldbplatformutil.getCompiler()
879-
f = tempfile.NamedTemporaryFile()
880-
cmd = [lldbplatformutil.getCompiler(), "-x", "c++", "-c", "-o", f.name, "-"]
881-
p = subprocess.Popen(
882-
cmd,
883-
stdin=subprocess.PIPE,
884-
stdout=subprocess.PIPE,
885-
stderr=subprocess.PIPE,
886-
universal_newlines=True,
887-
)
888-
stdout, stderr = p.communicate("struct __attribute__((%s)) Test {};" % attr)
889-
if attr in stderr:
890-
return "Compiler does not support attribute %s" % (attr)
891-
return None
881+
with temp_file.OnDiskTempFile() as f:
882+
cmd = [lldbplatformutil.getCompiler(), "-x", "c++", "-c", "-o", f.path, "-"]
883+
p = subprocess.Popen(
884+
cmd,
885+
stdin=subprocess.PIPE,
886+
stdout=subprocess.PIPE,
887+
stderr=subprocess.PIPE,
888+
universal_newlines=True,
889+
)
890+
stdout, stderr = p.communicate("struct __attribute__((%s)) Test {};" % attr)
891+
if attr in stderr:
892+
return "Compiler does not support attribute %s" % (attr)
893+
return None
892894

893895
return skipTestIfFn(compiler_doesnt_support_struct_attribute)
894896

@@ -902,21 +904,21 @@ def is_compiler_clang_with_call_site_info():
902904
if not compiler.startswith("clang"):
903905
return "Test requires clang as compiler"
904906

905-
f = tempfile.NamedTemporaryFile()
906-
cmd = (
907-
"echo 'int main() {}' | "
908-
"%s -g -glldb -O1 -S -emit-llvm -x c -o %s -" % (compiler_path, f.name)
909-
)
910-
if os.popen(cmd).close() is not None:
911-
return "Compiler can't compile with call site info enabled"
907+
with temp_file.OnDiskTempFile() as f:
908+
cmd = (
909+
"echo 'int main() {}' | "
910+
"%s -g -glldb -O1 -S -emit-llvm -x c -o %s -" % (compiler_path, f.path)
911+
)
912+
if os.popen(cmd).close() is not None:
913+
return "Compiler can't compile with call site info enabled"
912914

913-
with open(f.name, "r") as ir_output_file:
914-
buf = ir_output_file.read()
915+
with open(f.path, "r") as ir_output_file:
916+
buf = ir_output_file.read()
915917

916-
if "DIFlagAllCallsDescribed" not in buf:
917-
return "Compiler did not introduce DIFlagAllCallsDescribed IR flag"
918+
if "DIFlagAllCallsDescribed" not in buf:
919+
return "Compiler did not introduce DIFlagAllCallsDescribed IR flag"
918920

919-
return None
921+
return None
920922

921923
return skipTestIfFn(is_compiler_clang_with_call_site_info)(func)
922924

@@ -957,7 +959,7 @@ def is_compiler_clang_with_ubsan():
957959
)
958960

959961
# We need to write out the object into a named temp file for inspection.
960-
outputf = tempfile.NamedTemporaryFile()
962+
outputf = temp_file.OnDiskTempFile()
961963

962964
# Try to compile with ubsan turned on.
963965
if not _compiler_supports(
@@ -969,7 +971,7 @@ def is_compiler_clang_with_ubsan():
969971
return "Compiler cannot compile with -fsanitize=undefined"
970972

971973
# Check that we actually see ubsan instrumentation in the binary.
972-
cmd = "nm %s" % outputf.name
974+
cmd = "nm %s" % outputf.path
973975
with os.popen(cmd) as nm_output:
974976
if "___ubsan_handle_divrem_overflow" not in nm_output.read():
975977
return "Division by zero instrumentation is missing"
@@ -1037,40 +1039,37 @@ def skipUnlessAArch64MTELinuxCompiler(func):
10371039

10381040
def is_toolchain_with_mte():
10391041
compiler_path = lldbplatformutil.getCompiler()
1040-
f = tempfile.NamedTemporaryFile(delete=False)
1041-
if lldbplatformutil.getPlatform() == "windows":
1042-
return "MTE tests are not compatible with 'windows'"
1043-
1044-
# Note hostos may be Windows.
1045-
f.close()
1042+
with temp_file.OnDiskTempFile() as f:
1043+
if lldbplatformutil.getPlatform() == "windows":
1044+
return "MTE tests are not compatible with 'windows'"
1045+
1046+
cmd = f"{compiler_path} -x c -o {f.path} -"
1047+
if (
1048+
subprocess.run(
1049+
cmd, shell=True, input="int main() {}".encode()
1050+
).returncode
1051+
!= 0
1052+
):
1053+
# Cannot compile at all, don't skip the test
1054+
# so that we report the broken compiler normally.
1055+
return None
10461056

1047-
cmd = f"{compiler_path} -x c -o {f.name} -"
1048-
if (
1049-
subprocess.run(cmd, shell=True, input="int main() {}".encode()).returncode
1050-
!= 0
1051-
):
1052-
os.remove(f.name)
1053-
# Cannot compile at all, don't skip the test
1054-
# so that we report the broken compiler normally.
1057+
# We need the Linux headers and ACLE MTE intrinsics
1058+
test_src = """
1059+
#include <asm/hwcap.h>
1060+
#include <arm_acle.h>
1061+
#ifndef HWCAP2_MTE
1062+
#error
1063+
#endif
1064+
int main() {
1065+
void* ptr = __arm_mte_create_random_tag((void*)(0), 0);
1066+
}"""
1067+
cmd = f"{compiler_path} -march=armv8.5-a+memtag -x c -o {f.path} -"
1068+
res = subprocess.run(cmd, shell=True, input=test_src.encode())
1069+
if res.returncode != 0:
1070+
return "Toolchain does not support MTE"
10551071
return None
10561072

1057-
# We need the Linux headers and ACLE MTE intrinsics
1058-
test_src = """
1059-
#include <asm/hwcap.h>
1060-
#include <arm_acle.h>
1061-
#ifndef HWCAP2_MTE
1062-
#error
1063-
#endif
1064-
int main() {
1065-
void* ptr = __arm_mte_create_random_tag((void*)(0), 0);
1066-
}"""
1067-
cmd = f"{compiler_path} -march=armv8.5-a+memtag -x c -o {f.name} -"
1068-
res = subprocess.run(cmd, shell=True, input=test_src.encode())
1069-
os.remove(f.name)
1070-
if res.returncode != 0:
1071-
return "Toolchain does not support MTE"
1072-
return None
1073-
10741073
return skipTestIfFn(is_toolchain_with_mte)(func)
10751074

10761075

lldb/packages/Python/lldbsuite/test/dotest.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
from . import test_categories
4444
from . import test_result
4545
from ..support import seven
46+
from ..support import temp_file
4647

4748

4849
def is_exe(fpath):
@@ -780,8 +781,8 @@ def canRunLibcxxTests():
780781
return True, "libc++ always present"
781782

782783
if platform == "linux":
783-
with tempfile.NamedTemporaryFile() as f:
784-
cmd = [configuration.compiler, "-xc++", "-stdlib=libc++", "-o", f.name, "-"]
784+
with temp_file.OnDiskTempFile() as f:
785+
cmd = [configuration.compiler, "-xc++", "-stdlib=libc++", "-o", f.path, "-"]
785786
p = subprocess.Popen(
786787
cmd,
787788
stdin=subprocess.PIPE,
@@ -840,8 +841,8 @@ def canRunMsvcStlTests():
840841
if platform != "windows":
841842
return False, f"Don't know how to build with MSVC's STL on {platform}"
842843

843-
with tempfile.NamedTemporaryFile() as f:
844-
cmd = [configuration.compiler, "-xc++", "-o", f.name, "-E", "-"]
844+
with temp_file.OnDiskTempFile() as f:
845+
cmd = [configuration.compiler, "-xc++", "-o", f.path, "-E", "-"]
845846
p = subprocess.Popen(
846847
cmd,
847848
stdin=subprocess.PIPE,

0 commit comments

Comments
 (0)