Skip to content

Commit 0c80b54

Browse files
committed
Some updates/fixes to the creduce script.
This was motivated by changes to llvm's `not --crash` disabling symbolization but I ended up removing `not` from the script entirely because it returns differently depending on whether clang "crashes" or exits for some other reason. The script had to choose between calling `not` and `not --crash` and sometimes it was wrong. The script also now disables symbolization when we don't read the stack trace because symbolizing is kind of slow. Differential Revision: https://reviews.llvm.org/D91372
1 parent cf6565f commit 0c80b54

File tree

1 file changed

+27
-26
lines changed

1 file changed

+27
-26
lines changed

clang/utils/creduce-clang-crash.py

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
verbose = False
2424
creduce_cmd = None
2525
clang_cmd = None
26-
not_cmd = None
2726

2827
def verbose_print(*args, **kwargs):
2928
if verbose:
@@ -77,7 +76,7 @@ def __init__(self, crash_script, file_to_reduce):
7776
self.clang = clang_cmd
7877
self.clang_args = []
7978
self.expected_output = []
80-
self.is_crash = True
79+
self.needs_stack_trace = False
8180
self.creduce_flags = ["--tidy"]
8281

8382
self.read_clang_args(crash_script, file_to_reduce)
@@ -128,36 +127,36 @@ def read_expected_output(self):
128127
crash_output = re.sub(ansi_escape, '', crash_output.decode('utf-8'))
129128

130129
# Look for specific error messages
131-
regexes = [r"Assertion `(.+)' failed", # Linux assert()
132-
r"Assertion failed: (.+),", # FreeBSD/Mac assert()
133-
r"fatal error: error in backend: (.+)",
134-
r"LLVM ERROR: (.+)",
135-
r"UNREACHABLE executed (at .+)?!",
136-
r"LLVM IR generation of declaration '(.+)'",
137-
r"Generating code for declaration '(.+)'",
138-
r"\*\*\* Bad machine code: (.+) \*\*\*"]
130+
regexes = [r"Assertion .+ failed", # Linux assert()
131+
r"Assertion failed: .+,", # FreeBSD/Mac assert()
132+
r"fatal error: error in backend: .+",
133+
r"LLVM ERROR: .+",
134+
r"UNREACHABLE executed at .+?!",
135+
r"LLVM IR generation of declaration '.+'",
136+
r"Generating code for declaration '.+'",
137+
r"\*\*\* Bad machine code: .+ \*\*\*"]
139138
for msg_re in regexes:
140139
match = re.search(msg_re, crash_output)
141140
if match:
142-
msg = match.group(1)
141+
msg = match.group(0)
143142
result = [msg]
144143
print("Found message:", msg)
145-
146-
if "fatal error:" in msg_re:
147-
self.is_crash = False
148144
break
149145

150146
# If no message was found, use the top five stack trace functions,
151147
# ignoring some common functions
152148
# Five is a somewhat arbitrary number; the goal is to get a small number
153149
# of identifying functions with some leeway for common functions
154150
if not result:
151+
self.needs_stack_trace = True
155152
stacktrace_re = r'[0-9]+\s+0[xX][0-9a-fA-F]+\s*([^(]+)\('
156-
filters = ["PrintStackTraceSignalHandler",
157-
"llvm::sys::RunSignalHandlers",
158-
"SignalHandler", "__restore_rt", "gsignal", "abort"]
153+
filters = ["PrintStackTrace", "RunSignalHandlers", "CleanupOnSignal",
154+
"HandleCrash", "SignalHandler", "__restore_rt", "gsignal", "abort"]
155+
def skip_function(func_name):
156+
return any(name in func_name for name in filters)
157+
159158
matches = re.findall(stacktrace_re, crash_output)
160-
result = [x for x in matches if x and x.strip() not in filters][:5]
159+
result = [x for x in matches if x and not skip_function(x)][:5]
161160
for msg in result:
162161
print("Found stack trace function:", msg)
163162

@@ -184,10 +183,17 @@ def check_expected_output(self, args=None, filename=None):
184183
def write_interestingness_test(self):
185184
print("\nCreating the interestingness test...")
186185

187-
crash_flag = "--crash" if self.is_crash else ""
186+
# Disable symbolization if it's not required to avoid slow symbolization.
187+
disable_symbolization = ''
188+
if not self.needs_stack_trace:
189+
disable_symbolization = 'export LLVM_DISABLE_SYMBOLIZATION=1'
188190

189-
output = "#!/bin/bash\n%s %s %s >& t.log || exit 1\n" % \
190-
(pipes.quote(not_cmd), crash_flag, quote_cmd(self.get_crash_cmd()))
191+
output = """#!/bin/bash
192+
%s
193+
if %s >& t.log ; then
194+
exit 1
195+
fi
196+
""" % (disable_symbolization, quote_cmd(self.get_crash_cmd()))
191197

192198
for msg in self.expected_output:
193199
output += 'grep -F %s t.log || exit 1\n' % pipes.quote(msg)
@@ -372,7 +378,6 @@ def main():
372378
global verbose
373379
global creduce_cmd
374380
global clang_cmd
375-
global not_cmd
376381

377382
parser = ArgumentParser(description=__doc__,
378383
formatter_class=RawTextHelpFormatter)
@@ -382,9 +387,6 @@ def main():
382387
help="Name of the file to be reduced.")
383388
parser.add_argument('--llvm-bin', dest='llvm_bin', type=str,
384389
help="Path to the LLVM bin directory.")
385-
parser.add_argument('--llvm-not', dest='llvm_not', type=str,
386-
help="The path to the `not` executable. "
387-
"By default uses the llvm-bin directory.")
388390
parser.add_argument('--clang', dest='clang', type=str,
389391
help="The path to the `clang` executable. "
390392
"By default uses the llvm-bin directory.")
@@ -398,7 +400,6 @@ def main():
398400
llvm_bin = os.path.abspath(args.llvm_bin) if args.llvm_bin else None
399401
creduce_cmd = check_cmd('creduce', None, args.creduce)
400402
clang_cmd = check_cmd('clang', llvm_bin, args.clang)
401-
not_cmd = check_cmd('not', llvm_bin, args.llvm_not)
402403

403404
crash_script = check_file(args.crash_script[0])
404405
file_to_reduce = check_file(args.file_to_reduce[0])

0 commit comments

Comments
 (0)