[PATCH] D59440: add steps to preprocess file and reduce command line args
akhuang added a comment. @arichardson Will add you next time, sorry I didn't do so on this one! Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59440/new/ https://reviews.llvm.org/D59440 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D59440: add steps to preprocess file and reduce command line args
arichardson added a comment. @akhuang Thanks for getting this committed. Since it seems like a lot of this is taken from my script, could you please add me as a reviewer for the next patch so that I know which bits still need to be upstreamed? Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59440/new/ https://reviews.llvm.org/D59440 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D59440: add steps to preprocess file and reduce command line args
This revision was automatically updated to reflect the committed changes. Closed by commit rC356636: creduce-clang-crash.py: preprocess file + reduce commandline (authored by gbiv, committed by ). Changed prior to commit: https://reviews.llvm.org/D59440?vs=191598&id=191615#toc Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59440/new/ https://reviews.llvm.org/D59440 Files: utils/creduce-clang-crash.py Index: utils/creduce-clang-crash.py === --- utils/creduce-clang-crash.py +++ utils/creduce-clang-crash.py @@ -1,7 +1,5 @@ #!/usr/bin/env python """Calls C-Reduce to create a minimal reproducer for clang crashes. - -Requires C-Reduce and not (part of LLVM utils) to be installed. """ from argparse import ArgumentParser @@ -11,108 +9,232 @@ import sys import subprocess import pipes +import shlex +import tempfile +import shutil from distutils.spawn import find_executable -def create_test(build_script, llvm_not): +verbose = False +llvm_bin = None +creduce_cmd = None +not_cmd = None + +def check_file(fname): + if not os.path.isfile(fname): +sys.exit("ERROR: %s does not exist" % (fname)) + return fname + +def check_cmd(cmd_name, cmd_dir, cmd_path=None): """ - Create an interestingness test from the crash output. - Return as a string. + Returns absolute path to cmd_path if it is given, + or absolute path to cmd_dir/cmd_name. """ - # Get clang call from build script - # Assumes the call is the last line of the script - with open(build_script) as f: -cmd = f.readlines()[-1].rstrip('\n\r') + if cmd_path: +cmd = find_executable(cmd_path) +if cmd: + return cmd +sys.exit("ERROR: executable %s not found" % (cmd_path)) + + cmd = find_executable(cmd_name, path=cmd_dir) + if cmd: +return cmd + sys.exit("ERROR: %s not found in %s" % (cmd_name, cmd_dir)) + +def quote_cmd(cmd): + return ' '.join(arg if arg.startswith('$') else pipes.quote(arg) + for arg in cmd) + +def get_crash_cmd(crash_script): + with open(crash_script) as f: +# Assume clang call is on the last line of the script +line = f.readlines()[-1] +cmd = shlex.split(line) + +# Overwrite the script's clang with the user's clang path +new_clang = check_cmd('clang', llvm_bin) +cmd[0] = pipes.quote(new_clang) +return cmd - # Get crash output - p = subprocess.Popen(build_script, +def has_expected_output(crash_cmd, expected_output): + p = subprocess.Popen(crash_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) crash_output, _ = p.communicate() + return all(msg in crash_output for msg in expected_output) - output = ['#!/bin/bash'] - output.append('%s --crash %s >& t.log || exit 1' % (pipes.quote(llvm_not), - cmd)) - - # Add messages from crash output to the test - # If there is an Assertion failure, use that; otherwise use the - # last five stack trace functions +def get_expected_output(crash_cmd): + p = subprocess.Popen(crash_cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + crash_output, _ = p.communicate() + + # If there is an assertion failure, use that; + # otherwise use the last five stack trace functions assertion_re = r'Assertion `([^\']+)\' failed' assertion_match = re.search(assertion_re, crash_output) if assertion_match: -msg = assertion_match.group(1) -output.append('grep %s t.log || exit 1' % pipes.quote(msg)) +return [assertion_match.group(1)] else: stacktrace_re = r'#[0-9]+\s+0[xX][0-9a-fA-F]+\s*([^(]+)\(' matches = re.findall(stacktrace_re, crash_output) -del matches[:-5] -output += ['grep %s t.log || exit 1' % pipes.quote(msg) for msg in matches] +return matches[-5:] + +def write_interestingness_test(testfile, crash_cmd, expected_output, + file_to_reduce): + filename = os.path.basename(file_to_reduce) + if filename not in crash_cmd: +sys.exit("ERROR: expected %s to be in the crash command" % filename) + + # Replace all instances of file_to_reduce with a command line variable + output = ['#!/bin/bash', +'if [ -z "$1" ] ; then', +' f=%s' % (pipes.quote(filename)), +'else', +' f="$1"', +'fi'] + cmd = ['$f' if s == filename else s for s in crash_cmd] + + output.append('%s --crash %s >& t.log || exit 1' % (pipes.quote(not_cmd), + quote_cmd(cmd))) + + for msg in expected_output: +output.append('grep %s t.log || exit 1' % pipes.quote(msg)) + + with open(testfile, 'w') as f: +f.write('\n'.join(output)) + os.chmod(testfile, os.stat(testfile).st_mode | stat.S_IEXEC) - return output +def check_interestingness(testfile, file_to_reduce): + testfile = os.path.abspath(testfile)
[PATCH] D59440: add steps to preprocess file and reduce command line args
george.burgess.iv accepted this revision. george.burgess.iv added a comment. This revision is now accepted and ready to land. LGTM; thanks again! Will land shortly CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59440/new/ https://reviews.llvm.org/D59440 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D59440: add steps to preprocess file and reduce command line args
akhuang updated this revision to Diff 191598. akhuang added a comment. style nits, fixed thing in getting path to clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59440/new/ https://reviews.llvm.org/D59440 Files: clang/utils/creduce-clang-crash.py Index: clang/utils/creduce-clang-crash.py === --- clang/utils/creduce-clang-crash.py +++ clang/utils/creduce-clang-crash.py @@ -1,7 +1,5 @@ #!/usr/bin/env python """Calls C-Reduce to create a minimal reproducer for clang crashes. - -Requires C-Reduce and not (part of LLVM utils) to be installed. """ from argparse import ArgumentParser @@ -11,108 +9,232 @@ import sys import subprocess import pipes +import shlex +import tempfile +import shutil from distutils.spawn import find_executable -def create_test(build_script, llvm_not): +verbose = False +llvm_bin = None +creduce_cmd = None +not_cmd = None + +def check_file(fname): + if not os.path.isfile(fname): +sys.exit("ERROR: %s does not exist" % (fname)) + return fname + +def check_cmd(cmd_name, cmd_dir, cmd_path=None): """ - Create an interestingness test from the crash output. - Return as a string. + Returns absolute path to cmd_path if it is given, + or absolute path to cmd_dir/cmd_name. """ - # Get clang call from build script - # Assumes the call is the last line of the script - with open(build_script) as f: -cmd = f.readlines()[-1].rstrip('\n\r') - - # Get crash output - p = subprocess.Popen(build_script, + if cmd_path: +cmd = find_executable(cmd_path) +if cmd: + return cmd +sys.exit("ERROR: executable %s not found" % (cmd_path)) + + cmd = find_executable(cmd_name, path=cmd_dir) + if cmd: +return cmd + sys.exit("ERROR: %s not found in %s" % (cmd_name, cmd_dir)) + +def quote_cmd(cmd): + return ' '.join(arg if arg.startswith('$') else pipes.quote(arg) + for arg in cmd) + +def get_crash_cmd(crash_script): + with open(crash_script) as f: +# Assume clang call is on the last line of the script +line = f.readlines()[-1] +cmd = shlex.split(line) + +# Overwrite the script's clang with the user's clang path +new_clang = check_cmd('clang', llvm_bin) +cmd[0] = pipes.quote(new_clang) +return cmd + +def has_expected_output(crash_cmd, expected_output): + p = subprocess.Popen(crash_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) crash_output, _ = p.communicate() + return all(msg in crash_output for msg in expected_output) - output = ['#!/bin/bash'] - output.append('%s --crash %s >& t.log || exit 1' % (pipes.quote(llvm_not), - cmd)) +def get_expected_output(crash_cmd): + p = subprocess.Popen(crash_cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + crash_output, _ = p.communicate() - # Add messages from crash output to the test - # If there is an Assertion failure, use that; otherwise use the - # last five stack trace functions + # If there is an assertion failure, use that; + # otherwise use the last five stack trace functions assertion_re = r'Assertion `([^\']+)\' failed' assertion_match = re.search(assertion_re, crash_output) if assertion_match: -msg = assertion_match.group(1) -output.append('grep %s t.log || exit 1' % pipes.quote(msg)) +return [assertion_match.group(1)] else: stacktrace_re = r'#[0-9]+\s+0[xX][0-9a-fA-F]+\s*([^(]+)\(' matches = re.findall(stacktrace_re, crash_output) -del matches[:-5] -output += ['grep %s t.log || exit 1' % pipes.quote(msg) for msg in matches] +return matches[-5:] + +def write_interestingness_test(testfile, crash_cmd, expected_output, + file_to_reduce): + filename = os.path.basename(file_to_reduce) + if filename not in crash_cmd: +sys.exit("ERROR: expected %s to be in the crash command" % filename) + + # Replace all instances of file_to_reduce with a command line variable + output = ['#!/bin/bash', +'if [ -z "$1" ] ; then', +' f=%s' % (pipes.quote(filename)), +'else', +' f="$1"', +'fi'] + cmd = ['$f' if s == filename else s for s in crash_cmd] + + output.append('%s --crash %s >& t.log || exit 1' % (pipes.quote(not_cmd), + quote_cmd(cmd))) + + for msg in expected_output: +output.append('grep %s t.log || exit 1' % pipes.quote(msg)) - return output + with open(testfile, 'w') as f: +f.write('\n'.join(output)) + os.chmod(testfile, os.stat(testfile).st_mode | stat.S_IEXEC) + +def check_interestingness(testfile, file_to_reduce): + testfile = os.path.abspath(testfile) + + # Check that the test considers the original file interesting + with open(os.devnull, 'w') as devnull: +returncode = subprocess.call(testfile, stdout=
[PATCH] D59440: add steps to preprocess file and reduce command line args
george.burgess.iv added a comment. Just a few style nits for you, and this LGTM. I assume rnk and serge-sans-paille are content, so I'm happy to check this in for you once these are addressed. Thanks! Comment at: clang/utils/creduce-clang-crash.py:64 crash_output, _ = p.communicate() + for msg in expected_output: +if msg not in crash_output: nit: can be simplified to `return all(msg not in crash_output for msg in expected_output)` Comment at: clang/utils/creduce-clang-crash.py:116 + with open(os.devnull, 'w') as devnull: +p = subprocess.Popen(testfile, stdout=devnull) +p.communicate() nit: looks like you can use `returncode = subprocess.call(testfile, stdout=devnull)` here Comment at: clang/utils/creduce-clang-crash.py:124 + with open(os.devnull, 'w') as devnull: +p = subprocess.Popen([testfile, empty_file], stdout=devnull) +p.communicate() same `subprocess.call` nit Comment at: clang/utils/creduce-clang-crash.py:243 + #FIXME: reduce the clang crash command + nit: please add a space: `# FIXME` CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59440/new/ https://reviews.llvm.org/D59440 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D59440: add steps to preprocess file and reduce command line args
akhuang updated this revision to Diff 191409. akhuang added a comment. style things CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59440/new/ https://reviews.llvm.org/D59440 Files: clang/utils/creduce-clang-crash.py Index: clang/utils/creduce-clang-crash.py === --- clang/utils/creduce-clang-crash.py +++ clang/utils/creduce-clang-crash.py @@ -1,7 +1,5 @@ #!/usr/bin/env python """Calls C-Reduce to create a minimal reproducer for clang crashes. - -Requires C-Reduce and not (part of LLVM utils) to be installed. """ from argparse import ArgumentParser @@ -11,108 +9,238 @@ import sys import subprocess import pipes +import shlex +import tempfile +import shutil from distutils.spawn import find_executable -def create_test(build_script, llvm_not): +verbose = False +llvm_bin = None +creduce_cmd = None +not_cmd = None + +def check_file(fname): + if not os.path.isfile(fname): +sys.exit("ERROR: %s does not exist" % (fname)) + return fname + +def check_cmd(cmd_name, cmd_dir, cmd_path=None): """ - Create an interestingness test from the crash output. - Return as a string. + Returns absolute path to cmd_path if it is given, + or absolute path to cmd_dir/cmd_name. """ - # Get clang call from build script - # Assumes the call is the last line of the script - with open(build_script) as f: -cmd = f.readlines()[-1].rstrip('\n\r') - - # Get crash output - p = subprocess.Popen(build_script, + if cmd_path: +cmd = find_executable(cmd_path) +if cmd: + return cmd +sys.exit("ERROR: executable %s not found" % (cmd_path)) + + cmd = find_executable(cmd_name, path=cmd_dir) + if cmd: +return cmd + sys.exit("ERROR: %s not found in %s" % (cmd_name, cmd_dir)) + +def quote_cmd(cmd): + return ' '.join(arg if arg.startswith('$') else pipes.quote(arg) + for arg in cmd) + +def get_crash_cmd(crash_script): + with open(crash_script) as f: +# Assume clang call is on the last line of the script +line = f.readlines()[-1] +cmd = shlex.split(line) + +# Overwrite the script's clang with the user's clang path +clang_name = os.path.basename(cmd[0]) +new_clang = check_cmd(clang_name, llvm_bin) +cmd[0] = pipes.quote(new_clang) +return cmd + +def has_expected_output(crash_cmd, expected_output): + p = subprocess.Popen(crash_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) crash_output, _ = p.communicate() + for msg in expected_output: +if msg not in crash_output: + return False + return True - output = ['#!/bin/bash'] - output.append('%s --crash %s >& t.log || exit 1' % (pipes.quote(llvm_not), - cmd)) +def get_expected_output(crash_cmd): + p = subprocess.Popen(crash_cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + crash_output, _ = p.communicate() - # Add messages from crash output to the test - # If there is an Assertion failure, use that; otherwise use the - # last five stack trace functions + # If there is an assertion failure, use that; + # otherwise use the last five stack trace functions assertion_re = r'Assertion `([^\']+)\' failed' assertion_match = re.search(assertion_re, crash_output) if assertion_match: -msg = assertion_match.group(1) -output.append('grep %s t.log || exit 1' % pipes.quote(msg)) +return [assertion_match.group(1)] else: stacktrace_re = r'#[0-9]+\s+0[xX][0-9a-fA-F]+\s*([^(]+)\(' matches = re.findall(stacktrace_re, crash_output) -del matches[:-5] -output += ['grep %s t.log || exit 1' % pipes.quote(msg) for msg in matches] +return matches[-5:] + +def write_interestingness_test(testfile, crash_cmd, expected_output, + file_to_reduce): + filename = os.path.basename(file_to_reduce) + if filename not in crash_cmd: +sys.exit("ERROR: expected %s to be in the crash command" % filename) + + # Replace all instances of file_to_reduce with a command line variable + output = ['#!/bin/bash', +'if [ -z "$1" ] ; then', +' f=%s' % (pipes.quote(filename)), +'else', +' f="$1"', +'fi'] + cmd = ['$f' if s == filename else s for s in crash_cmd] + + output.append('%s --crash %s >& t.log || exit 1' % (pipes.quote(not_cmd), + quote_cmd(cmd))) + + for msg in expected_output: +output.append('grep %s t.log || exit 1' % pipes.quote(msg)) + + with open(testfile, 'w') as f: +f.write('\n'.join(output)) + os.chmod(testfile, os.stat(testfile).st_mode | stat.S_IEXEC) - return output +def check_interestingness(testfile, file_to_reduce): + testfile = os.path.abspath(testfile) + + # Check that the test considers the original file interesting + with open(os.devnull, 'w') as devnull: +
[PATCH] D59440: add steps to preprocess file and reduce command line args
serge-sans-paille added inline comments. Comment at: clang/utils/creduce-clang-crash.py:45 + result = [] + for i, arg in enumerate(cmd): +if arg.startswith('$'): Useless enumerate here. You could even use a list comprehension here ``` return ' '.join(arg if arg.startswith('$') else pipes.quote(arg) for arg in cmd) ``` Comment at: clang/utils/creduce-clang-crash.py:161 + for arg in args: +if (any(arg.startswith(a) for a in opts_startswith)): + continue useless parenthesis around test could be a list comprehension ``` result = [arg for arg in args if all(not arg.startswith(a) for a in opts_startswith)] ``` CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59440/new/ https://reviews.llvm.org/D59440 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D59440: add steps to preprocess file and reduce command line args
akhuang marked an inline comment as done. akhuang added inline comments. Comment at: clang/utils/creduce-clang-crash.py:106-117 + # Check that an empty file is not interesting + # file_to_reduce is hardcoded into the test, so this is a roundabout + # way to run it on an empty file + _, tmpfile = tempfile.mkstemp() + _, empty_file = tempfile.mkstemp() + shutil.copy(file_to_reduce, tmpfile) + shutil.copy(empty_file, file_to_reduce) rnk wrote: > Another way to do this without the complexity of swapping the files around is > to construct the interestingness test to take the path to the file as a > parameter (`$1`). CReduce always passes the path to the file being reduced as > the first argument. It seems like creduce isn't actually passing the filename as an argument (creduce had problems when I accidentally used the absolute path of the file as the default value when no arguments are found) CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59440/new/ https://reviews.llvm.org/D59440 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D59440: add steps to preprocess file and reduce command line args
akhuang updated this revision to Diff 191217. akhuang marked 2 inline comments as done. akhuang added a comment. Fixed typo where it was writing the abspath of the file to the interestingness test. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59440/new/ https://reviews.llvm.org/D59440 Files: clang/utils/creduce-clang-crash.py Index: clang/utils/creduce-clang-crash.py === --- clang/utils/creduce-clang-crash.py +++ clang/utils/creduce-clang-crash.py @@ -1,7 +1,5 @@ #!/usr/bin/env python """Calls C-Reduce to create a minimal reproducer for clang crashes. - -Requires C-Reduce and not (part of LLVM utils) to be installed. """ from argparse import ArgumentParser @@ -11,108 +9,245 @@ import sys import subprocess import pipes +import shlex +import tempfile +import shutil from distutils.spawn import find_executable -def create_test(build_script, llvm_not): +verbose = False +llvm_bin = None +creduce_cmd = None +not_cmd = None + +def check_file(fname): + if not os.path.isfile(fname): +sys.exit("ERROR: %s does not exist" % (fname)) + return fname + +def check_cmd(cmd_name, cmd_dir, cmd_path=None): """ - Create an interestingness test from the crash output. - Return as a string. + Returns absolute path to cmd_path if it is given, + or absolute path to cmd_dir/cmd_name. """ - # Get clang call from build script - # Assumes the call is the last line of the script - with open(build_script) as f: -cmd = f.readlines()[-1].rstrip('\n\r') - - # Get crash output - p = subprocess.Popen(build_script, + if cmd_path: +cmd = find_executable(cmd_path) +if cmd: + return cmd +sys.exit("ERROR: executable %s not found" % (cmd_path)) + + cmd = find_executable(cmd_name, path=cmd_dir) + if cmd: +return cmd + sys.exit("ERROR: %s not found in %s" % (cmd_name, cmd_dir)) + +def quote_cmd(cmd): + result = [] + for i, arg in enumerate(cmd): +if arg.startswith('$'): + result.append(arg) +else: + result.append(pipes.quote(arg)) + return ' '.join(result) + +def get_crash_cmd(crash_script): + with open(crash_script) as f: +# Assume clang call is on the last line of the script +line = f.readlines()[-1] +cmd = shlex.split(line) + +# Overwrite the script's clang with the user's clang path +clang_name = os.path.basename(cmd[0]) +new_clang = check_cmd(clang_name, llvm_bin) +cmd[0] = pipes.quote(new_clang) +return cmd + +def has_expected_output(crash_cmd, expected_output): + p = subprocess.Popen(crash_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) crash_output, _ = p.communicate() + for msg in expected_output: +if msg not in crash_output: + return False + return True - output = ['#!/bin/bash'] - output.append('%s --crash %s >& t.log || exit 1' % (pipes.quote(llvm_not), - cmd)) +def get_expected_output(crash_cmd): + p = subprocess.Popen(crash_cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + crash_output, _ = p.communicate() - # Add messages from crash output to the test - # If there is an Assertion failure, use that; otherwise use the - # last five stack trace functions + # If there is an assertion failure, use that; + # otherwise use the last five stack trace functions assertion_re = r'Assertion `([^\']+)\' failed' assertion_match = re.search(assertion_re, crash_output) if assertion_match: -msg = assertion_match.group(1) -output.append('grep %s t.log || exit 1' % pipes.quote(msg)) +return [assertion_match.group(1)] else: stacktrace_re = r'#[0-9]+\s+0[xX][0-9a-fA-F]+\s*([^(]+)\(' matches = re.findall(stacktrace_re, crash_output) -del matches[:-5] -output += ['grep %s t.log || exit 1' % pipes.quote(msg) for msg in matches] +return matches[-5:] + +def write_interestingness_test(testfile, crash_cmd, expected_output, + file_to_reduce): + filename = os.path.basename(file_to_reduce) + if filename not in crash_cmd: +sys.exit("ERROR: expected %s to be in the crash command" % filename) + + # Replace all instances of file_to_reduce with a command line variable + output = ['#!/bin/bash', +'if [ -z "$1" ] ; then', +' f=%s' % (pipes.quote(filename)), +'else', +' f="$1"', +'fi'] + cmd = ['$f' if s == filename else s for s in crash_cmd] + + output.append('%s --crash %s >& t.log || exit 1' % (pipes.quote(not_cmd), + quote_cmd(cmd))) + + for msg in expected_output: +output.append('grep %s t.log || exit 1' % pipes.quote(msg)) + + with open(testfile, 'w') as f: +f.write('\n'.join(output)) + os.chmod(testfile, os.stat(testfile).st_mode | stat.S_IEXEC) + +def check_interestingness(testf
[PATCH] D59440: add steps to preprocess file and reduce command line args
akhuang updated this revision to Diff 191199. akhuang marked an inline comment as done. akhuang added a comment. fixed array copy mistake CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59440/new/ https://reviews.llvm.org/D59440 Files: clang/utils/creduce-clang-crash.py Index: clang/utils/creduce-clang-crash.py === --- clang/utils/creduce-clang-crash.py +++ clang/utils/creduce-clang-crash.py @@ -1,7 +1,5 @@ #!/usr/bin/env python """Calls C-Reduce to create a minimal reproducer for clang crashes. - -Requires C-Reduce and not (part of LLVM utils) to be installed. """ from argparse import ArgumentParser @@ -11,108 +9,240 @@ import sys import subprocess import pipes +import shlex +import tempfile +import shutil from distutils.spawn import find_executable -def create_test(build_script, llvm_not): +verbose = False +llvm_bin = None +creduce_cmd = None +not_cmd = None + +def check_file(fname): + fname = os.path.abspath(fname) + if not os.path.isfile(fname): +sys.exit("ERROR: %s does not exist" % (fname)) + return fname + +def check_cmd(cmd_name, cmd_dir, cmd_path=None): """ - Create an interestingness test from the crash output. - Return as a string. + Returns absolute path to cmd_path if it is given, + or absolute path to cmd_dir/cmd_name. """ - # Get clang call from build script - # Assumes the call is the last line of the script - with open(build_script) as f: -cmd = f.readlines()[-1].rstrip('\n\r') - - # Get crash output - p = subprocess.Popen(build_script, + if cmd_path: +cmd = find_executable(cmd_path) +if cmd: + return cmd +sys.exit("ERROR: executable %s not found" % (cmd_path)) + + cmd = find_executable(cmd_name, path=cmd_dir) + if cmd: +return cmd + sys.exit("ERROR: %s not found in %s" % (cmd_name, cmd_dir)) + +def quote_cmd(cmd): + result = [] + for i, arg in enumerate(cmd): +if arg.startswith('$'): + result.append(arg) +else: + result.append(pipes.quote(arg)) + return ' '.join(result) + +def get_crash_cmd(crash_script): + with open(crash_script) as f: +# Assume clang call is on the last line of the script +line = f.readlines()[-1] +cmd = shlex.split(line) + +# Overwrite the script's clang with the user's clang path +clang_name = os.path.basename(cmd[0]) +new_clang = check_cmd(clang_name, llvm_bin) +cmd[0] = pipes.quote(new_clang) +return cmd + +def has_expected_output(crash_cmd, expected_output): + p = subprocess.Popen(crash_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) crash_output, _ = p.communicate() + for msg in expected_output: +if msg not in crash_output: + return False + return True - output = ['#!/bin/bash'] - output.append('%s --crash %s >& t.log || exit 1' % (pipes.quote(llvm_not), - cmd)) +def get_expected_output(crash_cmd): + p = subprocess.Popen(crash_cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + crash_output, _ = p.communicate() - # Add messages from crash output to the test - # If there is an Assertion failure, use that; otherwise use the - # last five stack trace functions + # If there is an assertion failure, use that; + # otherwise use the last five stack trace functions assertion_re = r'Assertion `([^\']+)\' failed' assertion_match = re.search(assertion_re, crash_output) if assertion_match: -msg = assertion_match.group(1) -output.append('grep %s t.log || exit 1' % pipes.quote(msg)) +return [assertion_match.group(1)] else: stacktrace_re = r'#[0-9]+\s+0[xX][0-9a-fA-F]+\s*([^(]+)\(' matches = re.findall(stacktrace_re, crash_output) -del matches[:-5] -output += ['grep %s t.log || exit 1' % pipes.quote(msg) for msg in matches] +return matches[-5:] + +def write_interestingness_test(testfile, crash_cmd, expected_output, + file_to_reduce): + # Replace all instances of file_to_reduce with a command line variable + _, filename = os.path.split(file_to_reduce) + output = ['#!/bin/bash', +'if [ -z "$1" ] ; then', +' f=%s' % (pipes.quote(file_to_reduce)), +'else', +' f="$1"', +'fi'] + cmd = ['$f' if s == filename else s for s in crash_cmd] + + output.append('%s --crash %s >& t.log || exit 1' % (pipes.quote(not_cmd), + quote_cmd(cmd))) + + for msg in expected_output: +output.append('grep %s t.log || exit 1' % pipes.quote(msg)) + + with open(testfile, 'w') as f: +f.write('\n'.join(output)) + os.chmod(testfile, os.stat(testfile).st_mode | stat.S_IEXEC) - return output +def check_interestingness(testfile, file_to_reduce): + # Check that the test considers the original file interesting + with open(os.devnull, '
[PATCH] D59440: add steps to preprocess file and reduce command line args
rnk added a comment. Aside from the buglet, I'm happy with this, but I wanted to wait until @george.burgess.iv takes a look. Comment at: clang/utils/creduce-clang-crash.py:44 + +def quote_cmd(cmd): + for i, arg in enumerate(cmd): This modifies cmd in place, so multiple calls to quote_cmd will get "more quoted" with more calls, right? CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59440/new/ https://reviews.llvm.org/D59440 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D59440: add steps to preprocess file and reduce command line args
akhuang updated this revision to Diff 191192. akhuang added a comment. Modify interestingness test to take file as input CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59440/new/ https://reviews.llvm.org/D59440 Files: clang/utils/creduce-clang-crash.py Index: clang/utils/creduce-clang-crash.py === --- clang/utils/creduce-clang-crash.py +++ clang/utils/creduce-clang-crash.py @@ -1,7 +1,5 @@ #!/usr/bin/env python """Calls C-Reduce to create a minimal reproducer for clang crashes. - -Requires C-Reduce and not (part of LLVM utils) to be installed. """ from argparse import ArgumentParser @@ -11,108 +9,238 @@ import sys import subprocess import pipes +import shlex +import tempfile +import shutil from distutils.spawn import find_executable -def create_test(build_script, llvm_not): +verbose = False +llvm_bin = None +creduce_cmd = None +not_cmd = None + +def check_file(fname): + fname = os.path.abspath(fname) + if not os.path.isfile(fname): +sys.exit("ERROR: %s does not exist" % (fname)) + return fname + +def check_cmd(cmd_name, cmd_dir, cmd_path=None): """ - Create an interestingness test from the crash output. - Return as a string. + Returns absolute path to cmd_path if it is given, + or absolute path to cmd_dir/cmd_name. """ - # Get clang call from build script - # Assumes the call is the last line of the script - with open(build_script) as f: -cmd = f.readlines()[-1].rstrip('\n\r') - - # Get crash output - p = subprocess.Popen(build_script, + if cmd_path: +cmd = find_executable(cmd_path) +if cmd: + return cmd +sys.exit("ERROR: executable %s not found" % (cmd_path)) + + cmd = find_executable(cmd_name, path=cmd_dir) + if cmd: +return cmd + sys.exit("ERROR: %s not found in %s" % (cmd_name, cmd_dir)) + +def quote_cmd(cmd): + for i, arg in enumerate(cmd): +if not arg.startswith('$'): + cmd[i] = pipes.quote(arg) + return ' '.join(cmd) + +def get_crash_cmd(crash_script): + with open(crash_script) as f: +# Assume clang call is on the last line of the script +line = f.readlines()[-1] +cmd = shlex.split(line) + +# Overwrite the script's clang with the user's clang path +clang_name = os.path.basename(cmd[0]) +new_clang = check_cmd(clang_name, llvm_bin) +cmd[0] = pipes.quote(new_clang) +return cmd + +def has_expected_output(crash_cmd, expected_output): + p = subprocess.Popen(crash_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) crash_output, _ = p.communicate() + for msg in expected_output: +if msg not in crash_output: + return False + return True - output = ['#!/bin/bash'] - output.append('%s --crash %s >& t.log || exit 1' % (pipes.quote(llvm_not), - cmd)) +def get_expected_output(crash_cmd): + p = subprocess.Popen(crash_cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + crash_output, _ = p.communicate() - # Add messages from crash output to the test - # If there is an Assertion failure, use that; otherwise use the - # last five stack trace functions + # If there is an assertion failure, use that; + # otherwise use the last five stack trace functions assertion_re = r'Assertion `([^\']+)\' failed' assertion_match = re.search(assertion_re, crash_output) if assertion_match: -msg = assertion_match.group(1) -output.append('grep %s t.log || exit 1' % pipes.quote(msg)) +return [assertion_match.group(1)] else: stacktrace_re = r'#[0-9]+\s+0[xX][0-9a-fA-F]+\s*([^(]+)\(' matches = re.findall(stacktrace_re, crash_output) -del matches[:-5] -output += ['grep %s t.log || exit 1' % pipes.quote(msg) for msg in matches] +return matches[-5:] + +def write_interestingness_test(testfile, crash_cmd, expected_output, + file_to_reduce): + # Replace all instances of file_to_reduce with a command line variable + _, filename = os.path.split(file_to_reduce) + output = ['#!/bin/bash', +'if [ -z "$1" ] ; then', +' f=%s' % (pipes.quote(file_to_reduce)), +'else', +' f="$1"', +'fi'] + cmd = ['$f' if s == filename else s for s in crash_cmd] + + output.append('%s --crash %s >& t.log || exit 1' % (pipes.quote(not_cmd), + quote_cmd(cmd))) + + for msg in expected_output: +output.append('grep %s t.log || exit 1' % pipes.quote(msg)) + + with open(testfile, 'w') as f: +f.write('\n'.join(output)) + os.chmod(testfile, os.stat(testfile).st_mode | stat.S_IEXEC) - return output +def check_interestingness(testfile, file_to_reduce): + # Check that the test considers the original file interesting + with open(os.devnull, 'w') as devnull: +p = subprocess.Popen(testfile, stdout=devnull) +p
[PATCH] D59440: add steps to preprocess file and reduce command line args
rnk added inline comments. Comment at: clang/utils/creduce-clang-crash.py:106-117 + # Check that an empty file is not interesting + # file_to_reduce is hardcoded into the test, so this is a roundabout + # way to run it on an empty file + _, tmpfile = tempfile.mkstemp() + _, empty_file = tempfile.mkstemp() + shutil.copy(file_to_reduce, tmpfile) + shutil.copy(empty_file, file_to_reduce) Another way to do this without the complexity of swapping the files around is to construct the interestingness test to take the path to the file as a parameter (`$1`). CReduce always passes the path to the file being reduced as the first argument. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59440/new/ https://reviews.llvm.org/D59440 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D59440: add steps to preprocess file and reduce command line args
akhuang updated this revision to Diff 191128. akhuang added a comment. fix some typos CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59440/new/ https://reviews.llvm.org/D59440 Files: clang/utils/creduce-clang-crash.py Index: clang/utils/creduce-clang-crash.py === --- clang/utils/creduce-clang-crash.py +++ clang/utils/creduce-clang-crash.py @@ -1,7 +1,5 @@ #!/usr/bin/env python """Calls C-Reduce to create a minimal reproducer for clang crashes. - -Requires C-Reduce and not (part of LLVM utils) to be installed. """ from argparse import ArgumentParser @@ -11,103 +9,243 @@ import sys import subprocess import pipes +import shlex +import tempfile +import shutil from distutils.spawn import find_executable -def create_test(build_script, llvm_not): +verbose = False +llvm_bin = None +creduce_cmd = None +not_cmd = None + +def check_file(fname): + fname = os.path.abspath(fname) + if not os.path.isfile(fname): +sys.exit("ERROR: %s does not exist" % (fname)) + return fname + +def check_cmd(cmd_name, cmd_dir, cmd_path=None): """ - Create an interestingness test from the crash output. - Return as a string. + Returns absolute path to cmd_path if it is given, + or absolute path to cmd_dir/cmd_name. """ - # Get clang call from build script - # Assumes the call is the last line of the script - with open(build_script) as f: -cmd = f.readlines()[-1].rstrip('\n\r') + if cmd_path: +cmd = find_executable(cmd_path) +if cmd: + return cmd +sys.exit("ERROR: executable %s not found" % (cmd_path)) + + cmd = find_executable(cmd_name, path=cmd_dir) + if cmd: +return cmd + sys.exit("ERROR: %s not found in %s" % (cmd_name, cmd_dir)) + +def quote_cmd(cmd): + return ' '.join(pipes.quote(s) for s in cmd) + +def get_crash_cmd(crash_script): + with open(crash_script) as f: +# Assume clang call is on the last line of the script +line = f.readlines()[-1] +cmd = shlex.split(line) - # Get crash output - p = subprocess.Popen(build_script, +# Overwrite the script's clang with the user's clang path +clang_name = os.path.basename(cmd[0]) +new_clang = check_cmd(clang_name, llvm_bin) +cmd[0] = pipes.quote(new_clang) +return cmd + +def has_expected_output(crash_cmd, expected_output): + p = subprocess.Popen(crash_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) crash_output, _ = p.communicate() + for msg in expected_output: +if msg not in crash_output: + return False + return True - output = ['#!/bin/bash'] - output.append('%s --crash %s >& t.log || exit 1' % (pipes.quote(llvm_not), - cmd)) +def get_expected_output(crash_cmd): + p = subprocess.Popen(crash_cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + crash_output, _ = p.communicate() - # Add messages from crash output to the test - # If there is an Assertion failure, use that; otherwise use the - # last five stack trace functions + # If there is an assertion failure, use that; + # otherwise use the last five stack trace functions assertion_re = r'Assertion `([^\']+)\' failed' assertion_match = re.search(assertion_re, crash_output) if assertion_match: -msg = assertion_match.group(1) -output.append('grep %s t.log || exit 1' % pipes.quote(msg)) +return [assertion_match.group(1)] else: stacktrace_re = r'#[0-9]+\s+0[xX][0-9a-fA-F]+\s*([^(]+)\(' matches = re.findall(stacktrace_re, crash_output) -del matches[:-5] -output += ['grep %s t.log || exit 1' % pipes.quote(msg) for msg in matches] +return matches[-5:] + +def write_interestingness_test(testfile, crash_cmd, expected_output): + output = ['#!/bin/bash'] + output.append('%s --crash %s >& t.log || exit 1' % (pipes.quote(not_cmd), + quote_cmd(crash_cmd))) + + for msg in expected_output: +output.append('grep %s t.log || exit 1' % pipes.quote(msg)) + + with open(testfile, 'w') as f: +f.write('\n'.join(output)) + os.chmod(testfile, os.stat(testfile).st_mode | stat.S_IEXEC) + +def check_interestingness(testfile, file_to_reduce): + # Check that the test considers the original file interesting + with open(os.devnull, 'w') as devnull: +p = subprocess.Popen(testfile, stdout=devnull) +p.communicate() + if p.returncode: +sys.exit("The interestingness test does not pass for the original file.") + + # Check that an empty file is not interesting + # file_to_reduce is hardcoded into the test, so this is a roundabout + # way to run it on an empty file + _, tmpfile = tempfile.mkstemp() + _, empty_file = tempfile.mkstemp() + shutil.copy(file_to_reduce, tmpfile) + shutil.copy(empty_file, file_to_reduce) + with open(os.devnull, 'w') as devnull: +p = subprocess.Popen(testfile, stdo
[PATCH] D59440: add steps to preprocess file and reduce command line args
akhuang updated this revision to Diff 190929. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59440/new/ https://reviews.llvm.org/D59440 Files: clang/utils/creduce-clang-crash.py Index: clang/utils/creduce-clang-crash.py === --- clang/utils/creduce-clang-crash.py +++ clang/utils/creduce-clang-crash.py @@ -1,7 +1,5 @@ #!/usr/bin/env python """Calls C-Reduce to create a minimal reproducer for clang crashes. - -Requires C-Reduce and not (part of LLVM utils) to be installed. """ from argparse import ArgumentParser @@ -11,103 +9,231 @@ import sys import subprocess import pipes +import shlex +import tempfile +import shutil from distutils.spawn import find_executable -def create_test(build_script, llvm_not): +verbose = False +llvm_bin = None +creduce_cmd = None +not_cmd = None + +def check_file(fname): + fname = os.path.abspath(fname) + if not os.path.isfile(fname): +sys.exit("ERROR: %s does not exist" % (fname)) + return fname + +def check_cmd(cmd_name, cmd_dir, cmd_path=None): """ - Create an interestingness test from the crash output. - Return as a string. + Returns absolute path to cmd_path if it is given, + or absolute path to cmd_dir/cmd_name. """ - # Get clang call from build script - # Assumes the call is the last line of the script - with open(build_script) as f: -cmd = f.readlines()[-1].rstrip('\n\r') - - # Get crash output - p = subprocess.Popen(build_script, + if cmd_path: +cmd = find_executable(cmd_path) +if cmd: + return cmd +sys.exit("ERROR: %s not found") + + cmd = find_executable(cmd_name, path=cmd_dir) + if cmd: +return cmd + sys.exit("ERROR: %s not found in %s" % (cmd_name, cmd_dir)) + +def quote_cmd(cmd): + return ' '.join(pipes.quote(s) for s in cmd) + +def get_crash_cmd(crash_script): + with open(crash_script) as f: +# Assume clang call is on the last line of the script +line = f.readlines()[-1] +cmd = shlex.split(line) + +# Overwrite the script's clang with the user's clang path +clang_name = os.path.basename(cmd[0]) +new_clang = check_cmd(clang_name, llvm_bin) +cmd[0] = pipes.quote(new_clang) +return cmd + +def has_expected_output(crash_cmd, expected_output): + p = subprocess.Popen(crash_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) crash_output, _ = p.communicate() + for msg in expected_output: +if msg not in crash_output: + return False + return True - output = ['#!/bin/bash'] - output.append('%s --crash %s >& t.log || exit 1' % (pipes.quote(llvm_not), - cmd)) +def get_expected_output(crash_cmd): + p = subprocess.Popen(crash_cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + crash_output, _ = p.communicate() - # Add messages from crash output to the test - # If there is an Assertion failure, use that; otherwise use the - # last five stack trace functions + # If there is an assertion failure, use that; + # otherwise use the last five stack trace functions assertion_re = r'Assertion `([^\']+)\' failed' assertion_match = re.search(assertion_re, crash_output) if assertion_match: -msg = assertion_match.group(1) -output.append('grep %s t.log || exit 1' % pipes.quote(msg)) +return [assertion_match.group(1)] else: stacktrace_re = r'#[0-9]+\s+0[xX][0-9a-fA-F]+\s*([^(]+)\(' matches = re.findall(stacktrace_re, crash_output) -del matches[:-5] -output += ['grep %s t.log || exit 1' % pipes.quote(msg) for msg in matches] +return matches[-5:] + +def write_interestingness_test(testfile, crash_cmd, expected_output): + output = ['#!/bin/bash'] + output.append('%s --crash %s >& t.log || exit 1' % (pipes.quote(not_cmd), + quote_cmd(crash_cmd))) + + for msg in expected_output: +output.append('grep %s t.log || exit 1' % pipes.quote(msg)) - return output + with open(testfile, 'w') as f: +f.write('\n'.join(output)) + os.chmod(testfile, os.stat(testfile).st_mode | stat.S_IEXEC) + +def check_interestingness(testfile, file_to_reduce): + # Check that the test considers the original file interesting + with open(os.devnull, 'w') as devnull: +p = subprocess.Popen(testfile, stdout=devnull) +p.communicate() + if p.returncode: +sys.exit("The interestingness test does not pass for the original file.") + + # Check that an empty file is not interesting + # file_to_reduce is hardcoded into the test, so this is a roundabout + # way to run it on an empty file + _, tmpfile = tempfile.mkstemp() + _, empty_file = tempfile.mkstemp() + shutil.copy(file_to_reduce, tmpfile) + shutil.copy(empty_file, file_to_reduce) + with open(os.devnull, 'w') as devnull: +p = subprocess.Popen(testfile, stdout=devnull) +p.communicate() + shutil.copy
[PATCH] D59440: add steps to preprocess file and reduce command line args
akhuang created this revision. akhuang added reviewers: rnk, george.burgess.iv. Herald added a reviewer: serge-sans-paille. Herald added a project: clang. Herald added a subscriber: cfe-commits. -try to preprocess the file before reducing -try to remove some command line arguments -now requires a llvm bin directory since the generated crash script doesn't have an absolute path for clang Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D59440 Files: clang/utils/creduce-clang-crash.py Index: clang/utils/creduce-clang-crash.py === --- clang/utils/creduce-clang-crash.py +++ clang/utils/creduce-clang-crash.py @@ -1,7 +1,5 @@ #!/usr/bin/env python """Calls C-Reduce to create a minimal reproducer for clang crashes. - -Requires C-Reduce and not (part of LLVM utils) to be installed. """ from argparse import ArgumentParser @@ -11,103 +9,231 @@ import sys import subprocess import pipes +import shlex +import tempfile +import shutil from distutils.spawn import find_executable -def create_test(build_script, llvm_not): +verbose = False +llvm_bin = None +creduce_cmd = None +not_cmd = None + +def check_file(fname): + fname = os.path.abspath(fname) + if not os.path.isfile(fname): +sys.exit("ERROR: %s does not exist" % (fname)) + return fname + +def check_cmd(cmd_name, cmd_dir, cmd_path=None): """ - Create an interestingness test from the crash output. - Return as a string. + Returns absolute path to cmd_path if it is given, + or absolute path to cmd_dir/cmd_name. """ - # Get clang call from build script - # Assumes the call is the last line of the script - with open(build_script) as f: -cmd = f.readlines()[-1].rstrip('\n\r') - - # Get crash output - p = subprocess.Popen(build_script, + if cmd_path: +cmd = find_executable(cmd_path) +if cmd: + return cmd +sys.exit("ERROR: %s not found") + + cmd = find_executable(cmd_name, path=cmd_dir) + if cmd: +return cmd + sys.exit("ERROR: %s not found in %s" % (cmd_name, cmd_dir)) + +def quote_cmd(cmd): + return ' '.join(pipes.quote(s) for s in cmd) + +def get_crash_cmd(crash_script): + with open(crash_script) as f: +# Assume clang call is on the last line of the script +line = f.readlines()[-1] +cmd = shlex.split(line) + +# Overwrite the script's clang with the user's clang path +clang_name = os.path.basename(cmd[0]) +new_clang = check_cmd(clang_name, llvm_bin) +cmd[0] = pipes.quote(new_clang) +return cmd + +def has_expected_output(crash_cmd, expected_output): + p = subprocess.Popen(crash_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) crash_output, _ = p.communicate() + for msg in expected_output: +if msg not in crash_output: + return False + return True - output = ['#!/bin/bash'] - output.append('%s --crash %s >& t.log || exit 1' % (pipes.quote(llvm_not), - cmd)) +def get_expected_output(crash_cmd): + p = subprocess.Popen(crash_cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + crash_output, _ = p.communicate() - # Add messages from crash output to the test - # If there is an Assertion failure, use that; otherwise use the - # last five stack trace functions + # If there is an assertion failure, use that; + # otherwise use the last five stack trace functions assertion_re = r'Assertion `([^\']+)\' failed' assertion_match = re.search(assertion_re, crash_output) if assertion_match: -msg = assertion_match.group(1) -output.append('grep %s t.log || exit 1' % pipes.quote(msg)) +return [assertion_match.group(1)] else: stacktrace_re = r'#[0-9]+\s+0[xX][0-9a-fA-F]+\s*([^(]+)\(' matches = re.findall(stacktrace_re, crash_output) -del matches[:-5] -output += ['grep %s t.log || exit 1' % pipes.quote(msg) for msg in matches] +return matches[-5:] + +def write_interestingness_test(testfile, crash_cmd, expected_output): + output = ['#!/bin/bash'] + output.append('%s --crash %s >& t.log || exit 1' % (pipes.quote(not_cmd), + quote_cmd(crash_cmd))) + + for msg in expected_output: +output.append('grep %s t.log || exit 1' % pipes.quote(msg)) - return output + with open(testfile, 'w') as f: +f.write('\n'.join(output)) + os.chmod(testfile, os.stat(testfile).st_mode | stat.S_IEXEC) + +def check_interestingness(testfile, file_to_reduce): + # Check that the test considers the original file interesting + with open(os.devnull, 'w') as devnull: +p = subprocess.Popen(testfile, stdout=devnull) +p.communicate() + if p.returncode: +sys.exit("The interestingness test does not pass for the original file.") + + # Check that an empty file is not interesting + # file_to_reduce is hardcoded into the test, so this is a roundabout +