Skip to content

Commit fba457d

Browse files
authored
[lit] Echo full RUN lines in case of external shells (#66408)
Before <https://reviews.llvm.org/D154984> and <https://reviews.llvm.org/D156954>, lit reported full RUN lines in a `Script:` section. Now, in the case of lit's internal shell, it's the execution trace that includes them. However, if lit is configured to use an external shell (e.g., bash, windows `cmd`), they aren't reported at all. A fix was requested at the following: * <https://reviews.llvm.org/D154984#4627605> * <https://discourse.llvm.org/t/rfc-improving-lits-debug-output/72839/35?u=jdenny-ornl> This patch does not address the case when the external shell is windows `cmd`. As discussed at <#65242>, it's not clear whether that's a use case that people still care about, and it seems to be generally broken anyway.
1 parent f223022 commit fba457d

File tree

7 files changed

+125
-8
lines changed

7 files changed

+125
-8
lines changed

llvm/utils/lit/lit/TestRunner.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1170,8 +1170,40 @@ def executeScript(test, litConfig, tmpBase, commands, cwd):
11701170
for i, ln in enumerate(commands):
11711171
match = re.fullmatch(kPdbgRegex, ln)
11721172
if match:
1173+
dbg = match.group(1)
11731174
command = match.group(2)
1174-
commands[i] = match.expand(": '\\1'; \\2" if command else ": '\\1'")
1175+
# Echo the debugging diagnostic to stderr.
1176+
#
1177+
# For that echo command, use 'set' commands to suppress the
1178+
# shell's execution trace, which would just add noise. Suppress
1179+
# the shell's execution trace for the 'set' commands by
1180+
# redirecting their stderr to /dev/null.
1181+
if command:
1182+
msg = f"'{dbg}': {shlex.quote(command.lstrip())}"
1183+
else:
1184+
msg = f"'{dbg}' has no command after substitutions"
1185+
commands[i] = (
1186+
f"{{ set +x; }} 2>/dev/null && "
1187+
f"echo {msg} >&2 && "
1188+
f"{{ set -x; }} 2>/dev/null"
1189+
)
1190+
# Execute the command, if any.
1191+
#
1192+
# 'command' might be something like:
1193+
#
1194+
# subcmd & PID=$!
1195+
#
1196+
# In that case, we need something like:
1197+
#
1198+
# echo_dbg && { subcmd & PID=$!; }
1199+
#
1200+
# Without the '{ ...; }' enclosing the original 'command', '&'
1201+
# would put all of 'echo_dbg && subcmd' in the background. This
1202+
# would cause 'echo_dbg' to execute at the wrong time, and a
1203+
# later kill of $PID would target the wrong process. We have
1204+
# seen the latter manage to terminate the shell running lit.
1205+
if command:
1206+
commands[i] += f" && {{ {command}; }}"
11751207
if test.config.pipefail:
11761208
f.write(b"set -o pipefail;" if mode == "wb" else "set -o pipefail;")
11771209
f.write(b"set -x;" if mode == "wb" else "set -x;")
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import lit.formats
2+
3+
config.test_format = lit.formats.ShTest(execute_external=True)
4+
config.name = "shtest-external-shell-kill"
5+
config.suffixes = [".txt"]
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# RUN: echo start
2+
# RUN: sleep 300 & PID=$!
3+
# RUN: sleep 2
4+
# RUN: kill $PID
5+
# RUN: echo end
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# DEFINE: %{empty} =
2+
# RUN: %{empty}
3+
# RUN: false
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# DEFINE: %{empty} =
2+
# RUN: %{empty}
3+
# RUN: false
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# This test exercises an external shell use case that, at least at one time,
2+
# appeared in the following tests:
3+
#
4+
# compiler-rt/test/fuzzer/fork-sigusr.test
5+
# compiler-rt/test/fuzzer/merge-sigusr.test
6+
# compiler-rt/test/fuzzer/sigint.test
7+
# compiler-rt/test/fuzzer/sigusr.test
8+
#
9+
# That is, a RUN line can be:
10+
#
11+
# cmd & PID=$!
12+
#
13+
# It is important that '&' only puts 'cmd' in the background and not the
14+
# debugging commands that lit inserts before 'cmd'. Otherwise:
15+
#
16+
# - The debugging commands might execute later than they are supposed to.
17+
# - A later 'kill $PID' can kill more than just 'cmd'. We've seen it even
18+
# manage to terminate the shell running lit.
19+
#
20+
# The last FileCheck directive below checks that the debugging commands for the
21+
# above RUN line are not killed and do execute at the right time.
22+
23+
# RUN: %{lit} -a %{inputs}/shtest-external-shell-kill | FileCheck %s
24+
# END.
25+
26+
# CHECK: Command Output (stdout):
27+
# CHECK-NEXT: --
28+
# CHECK-NEXT: start
29+
# CHECK-NEXT: end
30+
# CHECK-EMPTY:
31+
# CHECK-NEXT: --
32+
# CHECK-NEXT: Command Output (stderr):
33+
# CHECK-NEXT: --
34+
# CHECK-NEXT: RUN: at line 1: echo start
35+
# CHECK-NEXT: echo start
36+
# CHECK-NEXT: RUN: at line 2: sleep [[#]] & PID=$!

llvm/utils/lit/tests/shtest-run-at-line.py

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,46 @@
66
# END.
77

88

9-
# CHECK: Testing: 4 tests
9+
# CHECK: Testing: 6 tests
1010

1111

1212
# In the case of the external shell, we check for only RUN lines in stderr in
1313
# case some shell implementations format "set -x" output differently.
1414

1515
# CHECK-LABEL: FAIL: shtest-run-at-line :: external-shell/basic.txt
1616

17-
# CHECK: RUN: at line 4
18-
# CHECK: RUN: at line 5
19-
# CHECK-NOT: RUN
17+
# CHECK: Command Output (stderr)
18+
# CHECK-NEXT: --
19+
# CHECK-NEXT: {{^}}RUN: at line 4: true{{$}}
20+
# CHECK-NEXT: true
21+
# CHECK-NEXT: {{^}}RUN: at line 5: false{{$}}
22+
# CHECK-NEXT: false
23+
# CHECK-EMPTY:
24+
# CHECK-NEXT: --
25+
26+
# CHECK-LABEL: FAIL: shtest-run-at-line :: external-shell/empty-run-line.txt
27+
28+
# CHECK: Command Output (stderr)
29+
# CHECK-NEXT: --
30+
# CHECK-NEXT: {{^}}RUN: at line 2 has no command after substitutions{{$}}
31+
# CHECK-NEXT: {{^}}RUN: at line 3: false{{$}}
32+
# CHECK-NEXT: false
33+
# CHECK-EMPTY:
34+
# CHECK-NEXT: --
2035

2136
# CHECK-LABEL: FAIL: shtest-run-at-line :: external-shell/line-continuation.txt
2237

23-
# CHECK: RUN: at line 4
24-
# CHECK: RUN: at line 6
25-
# CHECK-NOT: RUN
38+
# The execution trace from an external sh-like shell might print the commands
39+
# from a pipeline in any order, so this time just check that lit suppresses the
40+
# trace of the echo command for each 'RUN: at line N: cmd-line'.
41+
42+
# CHECK: Command Output (stderr)
43+
# CHECK-NEXT: --
44+
# CHECK-NEXT: {{^}}RUN: at line 4: echo 'foo bar' | FileCheck
45+
# CHECK-NOT: RUN
46+
# CHECK: {{^}}RUN: at line 6: echo 'foo baz' | FileCheck
47+
# CHECK-NOT: RUN
48+
# CHECK: --
2649

2750

2851
# CHECK-LABEL: FAIL: shtest-run-at-line :: internal-shell/basic.txt
@@ -37,6 +60,16 @@
3760
# CHECK-NEXT: # executed command: false
3861
# CHECK-NOT: RUN
3962

63+
# CHECK-LABEL: FAIL: shtest-run-at-line :: internal-shell/empty-run-line.txt
64+
65+
# CHECK: Command Output (stdout)
66+
# CHECK-NEXT: --
67+
# CHECK-NEXT: # RUN: at line 2 has no command after substitutions
68+
# CHECK-NEXT: # RUN: at line 3
69+
# CHECK-NEXT: false
70+
# CHECK-NEXT: # executed command: false
71+
# CHECK-NOT: RUN
72+
4073
# CHECK-LABEL: FAIL: shtest-run-at-line :: internal-shell/line-continuation.txt
4174

4275
# CHECK: Command Output (stdout)

0 commit comments

Comments
 (0)